2019雅禮集訓 D2T1 two [模擬,線段樹]
阿新 • • 發佈:2019-01-07
題目描述:
樣例:
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[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; } }