当前位置: 代码迷 >> 综合 >> spoj Qtree6/bzoj 3637 Query on a tree VI(树链剖分+线段树/LCT)
  详细解决方案

spoj Qtree6/bzoj 3637 Query on a tree VI(树链剖分+线段树/LCT)

热度:5   发布时间:2023-12-17 03:27:30.0

题意:

思路:

首先,我们要开两颗线段树,一颗表示,当前节点为白时,和子树所组成的最大联通块大小是多少,另一颗表示,当前节点为黑时,和子树所组成的最大联通块大小是多少。
那么我们查询点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 whitestruct 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));}
}
  相关解决方案