【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序
2017-08-13 21:03
435 查看
题目大意
Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作: 1 x:把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:求x到y的路径的权值。
3 x y:在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行m次操作
n,m≤100000
题解
注意到操作1就是access操作,可以用LCT维护。 设fi=点i到根的路径权值,则操作2的答案为fx+fy−2flca+1。
如果只有操作1和操作2的话,就可以暴力往上跳,但是操作3就没那么好处理了。
所以我们可以用线段树+dfs序维护fi
access切换虚实边时一棵子树的f全部+1,另一棵子树的f全部−1
然后用倍增求LCA
时间复杂度:O(nlog2n)
代码
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<ctime> #include<utility> using namespace std; typedef long long ll; typedef pair<int,int> pii; int n,m; namespace seg { int s[4000010]; int t[4000010]; int n; void init() { n=0; memset(s,0,sizeof s); memset(t,0,sizeof t); } void at(int x,int v) { s[x]+=v; t[x]+=v; } void push(int x) { at(x*2,t[x]); at(x*2+1,t[x]); t[x]=0; } void add(int p,int l,int r,int v,int L,int R) { if(l<=L&&r>=R) { at(p,v); return; } if(t[p]) push(p); int mid=(L+R)>>1; if(l<=mid) add(p*2,l,r,v,L,mid); if(r>mid) add(p*2+1,l,r,v,mid+1,R); s[p]=max(s[p*2],s[p*2+1]); } int query(int p,int l,int r,int L,int R) { if(l<=L&&r>=R) return s[p]; if(t[p]) push(p); int mid=(L+R)>>1; int res=0; if(l<=mid) res=max(res,query(p*2,l,r,L,mid)); if(r>mid) res=max(res,query(p*2+1,l,r,mid+1,R)); return res; } } namespace tree { struct list { int v[200010]; int t[200010]; int h[100010]; int n; list() { n=0; memset(h,0,sizeof h); } void add(int x,int y) { n++; v =y; t =h[x]; h[x]=n; } }; list l; int bg[100010]; int ed[100010]; int ti; int f[100010][20]; int d[100010]; void init() { memset(f,0,sizeof f); ti=0; } void dfs(int x,int fa,int dep) { bg[x]=++ti; f[x][0]=fa; d[x]=dep; int i; for(i=1;i<=19;i++) f[x][i]=f[f[x][i-1]][i-1]; for(i=l.h[x];i;i=l.t[i]) if(l.v[i]!=fa) dfs(l.v[i],x,dep+1); ed[x]=ti; } int getlca(int x,int y) { if(d[x]<d[y]) swap(x,y); int i; for(i=19;i>=0;i--) if(d[f[x][i]]>=d[y]) x=f[x][i]; if(x==y) return x; for(i=19;i>=0;i--) if(f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } return f[x][0]; } } namespace lct { int f[100010]; int a[100010][2]; void init() { memset(f,0,sizeof f); memset(a,0,sizeof a); } int root(int x) { return a[f[x]][0]!=x&&a[f[x]][1]!=x; } void rotate(int x) { if(root(x)) return; int p=f[x]; int q=f[p]; int ps=(x==a[p][1]); int qs=(p==a[q][1]); int ch=a[x][ps^1]; if(!root(p)) a[q][qs]=x; a[x][ps^1]=p; a[p][ps]=ch; if(ch) f[ch]=p; f[p]=x; f[x]=q; } int splay(int x) { while(!root(x)) { int p=f[x]; if(!root(p)) if((x==a[p][1])^(p==a[f[p]][1])) rotate(p); else rotate(x); rotate(x); } } void access(int x) { int t=0; int y=x,z; while(x) { splay(x); if(t) { while(a[t][0]) t=a[t][0]; splay(t); seg::add(1,tree::bg[t],tree::ed[t],-1,1,n); } z=a[x][1]; a[x][1]=t; if(z) { while(a[z][0]) z=a[z][0]; splay(z); seg::add(1,tree::bg[z],tree::ed[z],1,1,n); } t=x; x=f[x]; } splay(y); } } int main() { lct::init(); seg::init(); tree::init(); // freopen("bzoj4817.in","r",stdin); // freopen("bzoj4817.out","w",stdout); scanf("%d%d",&n,&m); int i,op,x,y,ans; for(i=1;i<n;i++) { scanf("%d%d",&x,&y); tree::l.add(x,y); tree::l.add(y,x); } tree::dfs(1,0,1); for(i=2;i<=n;i++) lct::f[i]=tree::f[i][0]; for(i=1;i<=n;i++) seg::add(1,tree::bg[i],tree::bg[i],tree::d[i],1,n); for(i=1;i<=m;i++) { scanf("%d",&op); if(op==1) { scanf("%d",&x); lct::access(x); } else if(op==2) { scanf("%d%d",&x,&y); int lca=tree::getlca(x,y); ans=seg::query(1,tree::bg[x],tree::bg[x],1,n)+ seg::query(1,tree::bg[y],tree::bg[y],1,n)- 2*seg::query(1,tree::bg[lca],tree::bg[lca],1,n)+1; printf("%d\n",ans); } else { scanf("%d",&x); ans=seg::query(1,tree::bg[x],tree::ed[x],1,n); printf("%d\n",ans); } } return 0; }
相关文章推荐
- BZOJ.4817.[SDOI2017]树点涂色(LCT DFS序 线段树)
- [SDOI2017][bzoj4817] 树点涂色 [LCT+线段树]
- 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]
- 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
- 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
- BZOJ 4817 [Sdoi2017]树点涂色 ——LCT 线段树
- [LCT] BZOJ4817.[Sdoi2017]树点涂色
- [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)
- bzoj 4817: [Sdoi2017]树点涂色 LCT+树链剖分+线段树
- [LCT 线段树 dfs序] BZOJ 3779 重组病毒
- [BZOJ4817][SDOI2017]树点涂色(DFS序+LCA+树剖+LCT)
- BZOJ 3779 LCT 线段树 DFS序 坑
- BZOJ 4817 [LCT][线段树][树链剖分]
- [LCT] BZOJ 4817 [Sdoi2017]树点涂色
- BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)
- BZOJ 4817: [Sdoi2017]树点涂色
- [bzoj3545+3551][ONTAK2010]Peaks&&加强版(离线+线段树合并)||(kruskal重构树&&dfs序+主席树)
- [LCT维护最小生成树 || CDQ分治 || 线段树 并查集 dfs树] Codeforces 603E #334 (Div. 1) E. Pastoral Oddities
- Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序
- bzoj4817: [Sdoi2017]树点涂色