描述
你有两棵有根树,每棵各有 个顶点。让我们用整数 1 到 给每棵树的顶点编号。两棵树的根都是顶点 1。第一棵树的边都都是蓝色,第二棵树的边都是红色。
简明起见,我们称第一棵树是蓝色的,以及第二棵树是红色的。
当满足下面的两个条件下, 我们认为边 有害于边 :
1.边 的颜色不同于边 。
2.考虑与边 颜色相同的树,编号为 x, y 的两个顶点中有且只有一个同时在顶点 p 的子树与顶点 q 的子树里。
现在告诉你, 在阶段 1,有恰好一条蓝色的边被删除了,而在阶段 i,若我们删除了边 。那么在阶段 i+1 我们要删除的所有满足以下条件的边 :
1.边 未被删除。
2.存在一个 使得边 有害于 。
当某个阶段没有删除任何边时,则整个过程结束, 你需要回答,每个阶段哪些边将被删除。
注意,有害边的定义只依赖于开始删边之前的初始就拥有的两棵有根树。
输入
第一行为整数 n,表示两棵树的顶点数目。
接下来的一行包含 n-1 个正整数 ( ; 不等于 i),描述第一棵树的边。数字ai意味着第一棵树有一条边连接顶点ai和顶点 i。
接下来的一行包含 n-1 个正整数 ( ; 不等于 i),描述第二棵树的边。数字bi意味着第一棵树有一条边连接顶点bi和顶点 i。
接下来的再一行包含一个整数 idx( )表示在第一阶段中删除的蓝树的边的编号。
我们让每棵树的每条边按照他们在输入中的前后顺序从 1 到 -1 编号。
输出
对于每个阶段输出两行。
如果这个阶段删除的边是蓝色的,那么对应这一阶段的两行中,第一行必须为单词 Blue,否则为单词 Red。
对应的第二行包含所有此阶段删除的边的编号,按数字递增顺序输出。
样例输入
5 1
1 1 1
4 2 1 1
3
样例输出
Blue
3
Red
1 3
Blue
1 2
Red
2
提示
对于 的数据, 。
对于 的数据, 。
对于 的数据, 。
解析:
这种有两颗树的题真是莫名感觉毒瘤啊。。。
可能是因为我莫名其妙写了个树的封装?
思路:
首先这个限制,我们需要快速判断祖先后代关系,很好想到 序。
接下来所有的 ,都是指编号 的节点在对应树上的 进入时间和退出时间。
仔细看这个限制,发现 必然是有父子关系的,所以限制只会由儿子来体现。
再将限制具体化一,设
是其中的儿子,一条边
对
有害当且仅当一下两条中成立一条(假设
):
1.
且
2.
且
这里的 都是指 所在树的 。
所以我们可以用两棵个线段树来管辖两棵树,其中红树的线段树节点 中需要用一个 来记录一下蓝树中所有满足 的边的标号,节点内按照 递增的顺序存边,记为 。还要用一个 记录一下蓝树中所有满足 的边的标号,节点内按照 递减的顺序存边,记为 。蓝树的线段树作同样处理。
所以每次删除边只需要找到对应的线段树节点,并且在两个
末尾弹掉合法的边就行了。
可以用一个
数组来记录当前边有没有被删除,就不用每次专门清空线段树对应节点了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define puts put_s
#define cs const
namespace IO{
namespace IOONLY{
cs int Rlen=1<<16|1;
char buf[Rlen],*p1,*p2;
char obuf[Rlen],*p3=obuf;
char ch[23];
}
inline char get_char(){
using namespace IOONLY;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline void put_char(char c){
using namespace IOONLY;
*p3++=c;
if(p3==obuf+Rlen)fwrite(obuf,1,Rlen,stdout),p3=obuf;
}
inline void put_s(cs char *s){
for(;*s;s++)pc(*s);pc('\n');
}
inline void FLUSH(){
using namespace IOONLY;
fwrite(obuf,1,p3-obuf,stdout);p3=obuf;
}
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline void outint(int a){
using namespace IOONLY;
if(a==0)return pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
}
using namespace IO;
cs int N=200005;
int idx,now;
vector<int> ans,tmp;
struct Tree{
vector<int> edge[N],t1[N<<2],t2[N<<2];
int in[N],out[N],u[N],v[N];
bool del[N];
Tree(){}
inline void addedge(int u,int v){
edge[u].push_back(v);
edge[v].push_back(u);
++idx;
this->u[idx]=u;
this->v[idx]=v;
}
inline void dfs(int u,int fa){
in[u]=++idx;
for(re vector<int>::iterator v=edge[u].begin();v!=edge[u].end();++v){
if(fa==*v)continue;
dfs(*v,u);
}
out[u]=idx;
}
inline void insert_u(int k,int l,int r,cs int &pos,cs int &id){
t1[k].push_back(id);
if(l==r)return ;
int mid=(l+r)>>1;
if(mid<pos)insert_u(k<<1|1,mid+1,r,pos,id);
else insert_u(k<<1,l,mid,pos,id);
}
inline void insert_v(int k,int l,int r,cs int &pos,cs int &id){
t2[k].push_back(id);
if(l==r)return ;
int(mid)=(l+r)>>1;
if(mid<pos)insert_v(k<<1|1,mid+1,r,pos,id);
else insert_v(k<<1,l,mid,pos,id);
}
inline void pop(int id){
if(!del[id])del[id]=true,tmp.push_back(id);
}
}T[2];
inline bool cmp_v(cs int &a,cs int &b){
return T[!now].in[T[now].v[a]]<T[!now].in[T[now].v[b]];
}
inline bool cmp_u(cs int &a,cs int &b){
return T[!now].in[T[now].u[a]]>T[!now].in[T[now].u[b]];
}
inline void query(int k,int l,int r,cs int &ql,cs int &qr){
if(ql<=l&&r<=qr){
vector<int> &t1=T[!now].t1[k],&t2=T[!now].t2[k];
while(!t1.empty()){
re int i=t1.back();
if(T[now].in[T[!now].v[i]]>qr)T[!now].pop(i),t1.pop_back();
else break;
}
while(!t2.empty()){
re int i=t2.back();
if(T[now].in[T[!now].u[i]]<ql)T[!now].pop(i),t2.pop_back();
else break;
}
return ;
}
int mid=(l+r)>>1;
if(ql<=mid)query(k<<1,l,mid,ql,qr);
if(qr>mid)query(k<<1|1,mid+1,r,ql,qr);
}
int n;
int id[N];
signed main(){
n=getint();
for(now=0;now<2;++now,idx=0)for(int re i=2;i<=n;++i)T[now].addedge(i,getint());
idx=0;T[0].dfs(1,0);
idx=0;T[1].dfs(1,0);
for(int re i=1;i<n;++i)id[i]=i;
for(now=0;now<2;++now){
for(int re i=1;i<n;++i)if(T[!now].in[T[now].u[i]]>T[!now].in[T[now].v[i]])swap(T[now].u[i],T[now].v[i]);
sort(id+1,id+n,cmp_v);
for(int re i=1;i<n;++i)T[now].insert_u(1,1,n,T[!now].in[T[now].u[id[i]]],id[i]);
sort(id+1,id+n,cmp_u);
for(int re i=1;i<n;++i)T[now].insert_v(1,1,n,T[!now].in[T[now].v[id[i]]],id[i]);
}
idx=getint();T[0].del[idx]=true;
ans.push_back(idx);
for(now=0;ans.size();now^=1){
puts(now?"Red":"Blue");
tmp.clear();
for(int re i=0;i<ans.size();++i){
outint(ans[i]);pc(' ');
re int x=T[now].u[ans[i]],y=T[now].v[ans[i]];
if(T[now].in[x]<T[now].in[y])swap(x,y);
query(1,1,n,T[now].in[x],T[now].out[x]);
}pc('\n');
ans=tmp;
sort(ans.begin(),ans.end());
}
FLUSH();
return 0;
}