题意:
思路:
首先,我们要开两颗线段树,一颗表示,当前节点为白时,和子树所组成的最大联通块大小是多少,另一颗表示,当前节点为黑时,和子树所组成的最大联通块大小是多少。
那么我们查询点u的答案的时候,就向上找到最远的相同颜色的点v,点v所保存的答案就是u的答案(我们v为最远同色祖先)。
更新某个点u的颜色的时候,就是把u的父亲和最远同色祖先的父亲,这一条路径上的都更新(注意,黑白各更新一次,且将对应不同路径),为什么是把u的父亲和最远同色祖先的父亲更新一次,这个根据我们之前对他们的定义就能理解了,这里用树剖+线段树维护即可。
那么还有一个问题,怎么快速找到最远公共祖先,就是树剖爬,然后二分某个链即可(注意你二分的时候左右值分别表示的是什么)
最后,注意根,以及你在爬的时候,每个点表示的颜色
错误及反思:
卡了两天,真的毒啊,各种边界,各种细节,一个人慢慢摸索了好久才AC
这个代码在spoj过了,在bzojT了,把线段树改成树状数组应该就能AC了,可是我实在不想改了(不过代码写的很丑,主要是确实改烦了)
代码:
#include<bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N =100010;
int tot=0,tid=1,n,q;
int top[N],si[N],fa[N],first[N],son[N],depth[N],id[N],rnk[N];
int cnt[N*4],segtree[2][N*4],lazy[2][N*4];//0 for white 1 for black
// cnt calculate for white so 0 for black 1 for white
struct E{
int to,next;
}e[N*2];
void build(int l,int r,int rt){
if(l==r){
segtree[1][rt]=si[rnk[l]];
segtree[0][rt]=1;
return ;
}
int m=(l+r)/2;
build(lson); build(rson);
}
void addedge(int x,int y){
e[tot].to=y;
e[tot].next=first[x];
first[x]=tot++;
}
void dfs1(int now,int bef,int dep){
fa[now]=bef;
depth[now]=dep;
si[now]=1;
for(int i=first[now];i!=-1;i=e[i].next)
if(e[i].to!=bef){
dfs1(e[i].to,now,dep+1);
si[now]+=si[e[i].to];
if(son[now]==-1) son[now]=e[i].to;
else son[now]=si[e[i].to]>si[son[now]]?e[i].to:son[now];
}
}
void dfs2(int now,int tp){
top[now]=tp;
id[now]=tid++;
if(son[now]!=-1) dfs2(son[now],tp);
for(int i=first[now];i!=-1;i=e[i].next)
if(e[i].to!=fa[now]&&e[i].to!=son[now])
dfs2(e[i].to,e[i].to);
}
void init(){
memset(first,-1,sizeof(first));
memset(son,-1,sizeof(son));
}
void pushdown(int x,int l,int r,int rt){
if(lazy[x][rt]){
lazy[x][rt<<1]+=lazy[x][rt];
lazy[x][rt<<1|1]+=lazy[x][rt];
segtree[x][rt<<1]+=lazy[x][rt];
segtree[x][rt<<1|1]+=lazy[x][rt];
lazy[x][rt]=0;
}
}
void changecnt(int p,int l,int r,int rt){
if(l==r){
cnt[rt]=!cnt[rt];
return ;
}
int m=(l+r)/2;
if(m>=p) changecnt(p,lson);
else changecnt(p,rson);
cnt[rt]=cnt[rt<<1]+cnt[rt<<1|1];
}
void changeseg(int L,int R,int v,int l,int r,int rt,int x){
if(L<=l&&R>=r){
lazy[x][rt]+=v;
segtree[x][rt]+=v;
return ;
}
pushdown(x,l,r,rt);
int m=(l+r)/2;
if(L<=m) changeseg(L,R,v,lson,x);
if(R>m) changeseg(L,R,v,rson,x);
}
int querycnt(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r) return cnt[rt];
int m=(l+r)/2,ans=0;
if(m>=L) ans+=querycnt(L,R,lson);
if(m<R) ans+=querycnt(L,R,rson);
return ans;
}
int queryseg(int p,int l,int r,int rt,int x){
if(l==r)return segtree[x][rt];
int m=(l+r)/2;
pushdown(x,l,r,rt);
if(m>=p) return queryseg(p,lson,x);
return queryseg(p,rson,x);
}
int getans(int u){
int f=top[u],col=querycnt(id[u],id[u],1,n,1);
while(f!=1){
int x=querycnt(id[f],id[u],1,n,1);
if(col&&x!=depth[u]-depth[f]+1) break;
if(!col&&x) break;
if(col!=querycnt(id[fa[f]],id[fa[f]],1,n,1)) break;
u=fa[f];
f=top[u];
}
while(id[u]>id[f]+1){
int m=(id[u]+id[f])/2;
int x=querycnt(m,id[u],1,n,1);
if(col){
if(x==depth[u]-depth[rnk[m]]+1) u=rnk[m];
else f=rnk[m];
}
else{
if(x==0) u=rnk[m];
else f=rnk[m];
}
}
if(querycnt(id[fa[u]],id[fa[u]],1,n,1)==col) u=fa[u];
return queryseg(id[u],1,n,1,!col);
}
void modify(int u){
int v=u;
int col=querycnt(id[u],id[u],1,n,1),num=queryseg(id[u],1,n,1,!col);
changecnt(id[u],1,n,1);
if(u==1) return ;
u=fa[u];
int f=top[u];
while(f!=1){
int x=querycnt(id[f],id[u],1,n,1);
if(col&&x!=depth[u]-depth[f]+1) break;
else if(col) changeseg(id[f],id[u],-num,1,n,1,!col);
if(!col&&x) break;
else if(!col) changeseg(id[f],id[u],-num,1,n,1,!col);
u=fa[f];
f=top[u];
}
while(id[u]>id[f]+1){
int m=(id[u]+id[f])/2;
int x=querycnt(m,id[u],1,n,1);
if(col){
if(x==depth[u]-depth[rnk[m]]+1){
changeseg(m+1,id[u],-num,1,n,1,!col);
u=rnk[m];
}
else f=rnk[m];
}
else{
if(x==0){
changeseg(m+1,id[u],-num,1,n,1,!col);
u=rnk[m];
}
else f=rnk[m];
}
}
if(u!=f&&col==querycnt(id[u],id[u],1,n,1)) changeseg(id[u],id[u],-num,1,n,1,!col);
if(col!=querycnt(id[u],id[u],1,n,1)) f=u;
changeseg(id[f],id[f],-num,1,n,1,!col);
u=v;
col=!col;
num=queryseg(id[u],1,n,1,!col);
u=fa[u];
f=top[u];
while(f!=1){
int x=querycnt(id[f],id[u],1,n,1);
if(col&&x!=depth[u]-depth[f]+1) break;
else if(col) changeseg(id[f],id[u],num,1,n,1,!col);
if(!col&&x) break;
else if(!col) changeseg(id[f],id[u],num,1,n,1,!col);
u=fa[f];
f=top[u];
}
while(id[u]>id[f]+1){
int m=(id[u]+id[f])/2;
int x=querycnt(m,id[u],1,n,1);
if(col){
if(x==depth[u]-depth[rnk[m]]+1){
changeseg(m+1,id[u],num,1,n,1,!col);
u=rnk[m];
}
else f=rnk[m];
}
else{
if(x==0){
changeseg(m+1,id[u],num,1,n,1,!col);
u=rnk[m];
}
else f=rnk[m];
}
}
if(u!=f&&col==querycnt(id[u],id[u],1,n,1)) changeseg(id[u],id[u],num,1,n,1,!col);
if(col!=querycnt(id[u],id[u],1,n,1)) f=u;
changeseg(id[f],id[f],num,1,n,1,!col);
return ;
}
int main(){
init();
scanf("%d",&n);
for(int i=0,u,v;i<n-1;i++){
scanf("%d%d",&u,&v);
addedge(u,v); addedge(v,u);
}
dfs1(1,1,1); dfs2(1,1);
for(int i=1;i<=n;i++) rnk[id[i]]=i;
build(1,n,1);
scanf("%d",&q);
while(q--){
int k,u;
scanf("%d%d",&k,&u);
if(k) modify(u);
else printf("%d\n",getans(u));
}
}