题目描述:
样例:
input:
5 1
1 1 1
4 2 1 1
3
output:
Blue
3
Red
1 3
Blue
1 2
Red
2
数据范围:
标签:模拟,线段树
没错,你没有看错,这题标签就是模拟。
然而我还是不会做
首先很容易想到用dfs序判断一个点是否在另一个点的子树内。
然后写个\(n^2\)暴力就有60分了。
考虑用数据结构优化:
对于蓝树中的一条边(x,y),记u为两点在红树中dfs序较小的点,v为较大的点。
那么若\((x,y)\)对\((a,b)(dfn[a]<dfn[b])\)有害,则有\(dfn[b]<=dfn[u]<=low[b],dfn[v]>low[b]\)或\(dfn[b]<=dfn[v]<=low[b],dfn[u]<dfn[b]\)
用两棵线段树分别维护两种情况:
一棵以\(dfn[u]\)为下标,以\(dfn[v]\)单调递增的顺序在每一个线段树节点\([L,R]\)中排列。
一棵以\(dfn[v]\)为下标,以\(dfn[u]\)单调递减的顺序在每一个线段树节点\([L,R]\)中排列。
那么每次在一个节点中删点就相当于删除尾端的若干个元素。
分析一下就会发现这时间、空间复杂度都是\(O(nlogn)\)的。
口胡完了,代码够你写的,毕竟两种情况分别写真的很烦。我写了4kb。
所以说这是模拟嘛……
#include<bits/stdc++.h>
namespace my_std{
using namespace std;
#define mod 998244353
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[T][x],v;(v=edge[T][i].t,i);i=edge[T][i].nxt)
#define sz 200020
typedef long long ll;
template<typename T>
inline void read(T& t)
{
t=0;char f=0,ch=getchar();
double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.')
{
ch=getchar();
while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();
}
t=(f?-t:t);
}
template<typename T,typename... Args>
inline void read(T& t,Args&... args){read(t); read(args...);}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.txt","r",stdin);
#endif
}
inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
int n,m;
int T;
struct hh{int t,nxt;}edge[2][sz<<1];
int head[2][sz],ecnt;
void make_edge(int f,int t)
{
edge[T][++ecnt]=(hh){t,head[T][f]};
head[T][f]=ecnt;
edge[T][++ecnt]=(hh){f,head[T][t]};
head[T][t]=ecnt;
}
int dfn[2][sz],low[2][sz],cnt;
void dfs(int x,int fa)
{
dfn[T][x]=++cnt;
go(x) if (v!=fa) dfs(v,x);
low[T][x]=cnt;
}
int u[2][sz],v[2][sz],id[sz];
vector<int>t1[2][sz<<2],t2[2][sz<<2];
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
void ins1(int k,int l,int r,int x,int w)
{
t1[T][k].push_back(w);
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) ins1(lson,x,w);
else ins1(rson,x,w);
}
void ins2(int k,int l,int r,int x,int w)
{
t2[T][k].push_back(w);
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) ins2(lson,x,w);
else ins2(rson,x,w);
}
bool del[2][sz];
int tmp[sz],c,ans[sz],cc;
void query1(int k,int l,int r,int x,int y)
{
if (x<=l&&r<=y)
{
while (t1[T][k].size())
{
int t=t1[T][k].back();
if (dfn[T^1][u[T][t]]<x)
{
t1[T][k].pop_back();
if (!del[T][t]) ans[++cc]=t,del[T][t]=1;
}
else break;
}
return;
}
int mid=(l+r)>>1;
if (x<=mid) query1(lson,x,y);
if (y>mid) query1(rson,x,y);
}
void query2(int k,int l,int r,int x,int y)
{
if (x<=l&&r<=y)
{
while (t2[T][k].size())
{
int t=t2[T][k].back();
if (dfn[T^1][v[T][t]]>y)
{
t2[T][k].pop_back();
if (!del[T][t]) ans[++cc]=t,del[T][t]=1;
}
else break;
}
return;
}
int mid=(l+r)>>1;
if (x<=mid) query2(lson,x,y);
if (y>mid) query2(rson,x,y);
}
inline bool cmp1(const int &x,const int &y){return dfn[T^1][u[T][x]]>dfn[T^1][u[T][y]];}
inline bool cmp2(const int &x,const int &y){return dfn[T^1][v[T][x]]<dfn[T^1][v[T][y]];}
void IN()
{
int x;
rep(i,2,n) read(x),make_edge(x,i),u[T][i-1]=x,v[T][i-1]=i;
dfs(1,0);
}
void init()
{
rep(i,1,n-1) if (dfn[T^1][u[T][i]]>dfn[T^1][v[T][i]]) swap(u[T][i],v[T][i]);
sort(id+1,id+n,cmp1);
rep(i,1,n-1) ins1(1,1,n,dfn[T^1][v[T][id[i]]],id[i]);
sort(id+1,id+n,cmp2);
rep(i,1,n-1) ins2(1,1,n,dfn[T^1][u[T][id[i]]],id[i]);
}
int main()
{
freopen("two.in","r",stdin);freopen("two.out","w",stdout);
read(n);
int x,y;
T=0;ecnt=cnt=0;IN();T=1;ecnt=cnt=0;IN();
rep(i,1,n-1) id[i]=i;
T=0;init();T=1;init();
T=0;
read(tmp[c=1]);del[0][tmp[1]]=1;
printf("Blue\n%d\n",tmp[1]);
while (233)
{
cc=0;T^=1;
rep(i,1,c)
{
x=u[T^1][tmp[i]],y=v[T^1][tmp[i]];
if (dfn[T^1][x]<dfn[T^1][y]) swap(x,y);
query1(1,1,n,dfn[T^1][x],low[T^1][x]);
query2(1,1,n,dfn[T^1][x],low[T^1][x]);
}
if (!cc) return 0;
puts(T?"Red":"Blue");
sort(ans+1,ans+cc+1);
rep(i,1,cc-1) printf("%d ",tmp[i]=ans[i]);
printf("%d\n",tmp[cc]=ans[cc]);
c=cc;
}
}