bzoj4817 [Sdoi2017]树点涂色
2017-04-12 10:29
513 查看
吐槽一波怎么今年的山东OI这么水……(装B
不难看出第一种操作就是LCT的access,那么每个点到根节点的颜色种数就是虚边数量+1,两点间颜色种数同理……
第三种操作可以用把每个虚边挂着的点的子树权值全部+1的方式来维护,那么直接LCT+区间修改区间求max的线段树维护即可,复杂度$O(n\log^2 n)$。
/************************************************************** Problem: 4817 User: _Angel_ Language: C++ Result: Accepted Time:5500 ms Memory:21092 kb ****************************************************************/ #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define isroot(x) ((x)->p==null||((x)!=(x)->p->ch[0]&&(x)!=(x)->p->ch[1])) #define dir(x) ((x)==(x)->p->ch[1]) using namespace std; const int maxn=100010; struct node{node *ch[2],*p;}null[maxn]; void dfs(int); int LCA(int,int); node *access(node*); node *getroot(node*); void splay(node*); void rot(node*,int); void modify(int,int,int); int query(int,int,int); int mx[maxn<<2]={0},lazy[maxn<<2]={0}; vector<int>G[maxn]; int f[maxn][20],d[maxn],dfn[maxn],finish[maxn],tim=0; int n,m,lgn=0,s,t,k,x,y; int main(){ null->ch[0]=null->ch[1]=null->p=null; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)null[i].ch[0]=null[i].ch[1]=null[i].p=null; for(int i=1;i<n;i++){ scanf("%d%d",&x,&y); G[x].push_back(y); G[y].push_back(x); } dfs(1); for(int j=1;j<=lgn;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1]; while(m--){ scanf("%d%d",&k,&x); if(k==1)access(null+x); else if(k==2){ scanf("%d",&y); s=t=dfn[x]; int ans=query(1,n,1); s=t=dfn[y]; ans+=query(1,n,1); s=t=dfn[LCA(x,y)]; ans-=query(1,n,1)<<1; printf("%d\n",ans+1); } else if(k==3){ s=dfn[x]; t=finish[x]; printf("%d\n",query(1,n,1)+1); } } return 0; } void dfs(int x){ dfn[x]=++tim; d[x]=d[f[x][0]]+1; null[x].p=null+f[x][0]; while((1<<lgn)<d[x])lgn++; for(int i=0;i<(int)G[x].size();i++)if(G[x][i]!=f[x][0]){ f[G[x][i]][0]=x; dfs(G[x][i]); } finish[x]=tim; if(f[x][0]){ s=dfn[x]; t=finish[x]; k=1; modify(1,n,1); } } int LCA(int x,int y){ if(d[x]!=d[y]){ if(d[x]<d[y])swap(x,y); for(int i=lgn;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i]; } if(x==y)return x; for(int i=lgn;i>=0;i--)if(f[x][i]!=f[y][i]){ x=f[x][i]; y=f[y][i]; } return f[x][0]; } node *access(node *x){ node *y=null; while(x!=null){ splay(x); if(x->ch[1]!=null){ node *u=x->ch[1]; x->ch[1]=null; u=getroot(u); s=dfn[u-null]; t=finish[u-null]; k=1; modify(1,n,1); } if(y!=null){ y=getroot(y); s=dfn[y-null]; t=finish[y-null]; k=-1; modify(1,n,1); } x->ch[1]=y; y=x; x=x->p; } return y; } node *getroot(node *x){ splay(x); while(x->ch[0]!=null)x=x->ch[0]; splay(x); return x; } void splay(node *x){ while(!isroot(x)){ if(isroot(x->p)){ rot(x->p,dir(x)^1); break; } if(dir(x)==dir(x->p))rot(x->p->p,dir(x->p)^1); else rot(x->p,dir(x)^1); rot(x->p,dir(x)^1); } } inline void rot(node *x,int d){ node *y=x->ch[d^1]; if((x->ch[d^1]=y->ch[d])!=null)y->ch[d]->p=x; y->p=x->p; if(!isroot(x))x->p->ch[dir(x)]=y; (y->ch[d]=x)->p=y; } void modify(int l,int r,int rt){ if(s<=l&&t>=r){ mx[rt]+=k; lazy[rt]+=k; return; } int mid=(l+r)>>1; if(s<=mid)modify(l,mid,rt<<1); if(t>mid)modify(mid+1,r,rt<<1|1); mx[rt]=max(mx[rt<<1],mx[rt<<1|1])+lazy[rt]; } int query(int l,int r,int rt){ if(s<=l&&t>=r)return mx[rt]; int mid=(l+r)>>1,ans=0; if(s<=mid)ans=max(ans,query(l,mid,rt<<1)); if(t>mid)ans=max(ans,query(mid+1,r,rt<<1|1)); return ans+lazy[rt]; }View Code
ps:如果没记错的话,这题应该是重组病毒那题的超级弱化版……
相关文章推荐
- [BZOJ4817][SDOI2017]树点涂色(DFS序+LCA+树剖+LCT)
- bzoj4817 [Sdoi2017]树点涂色
- [BZOJ4817][SDOI2017]树点涂色
- [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)
- [BZOJ4817][SDOI2017]树点涂色(LCT+线段树+差分)
- bzoj4817 [Sdoi2017]树点涂色
- [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)
- BZOJ 4817 [Sdoi2017]树点涂色 ——LCT 线段树
- [bzoj4817][Sdoi2017]树点涂色
- 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树
- Bzoj4817 [Sdoi2017]树点涂色
- [LCT] BZOJ 4817 [Sdoi2017]树点涂色
- 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]
- BZOJ4817 [Sdoi2017]树点涂色(洛谷P3703)
- 【BZOJ4817】【SDOI2017】树点染色
- 【bzoj4817】[Sdoi2017]树点涂色 LCT+LCA+线段树
- BZOJ4817 [Sdoi2017]树点涂色
- bzoj 4818: [Sdoi2017]序列计数
- 【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序
- [BZOJ]4818: [Sdoi2017]序列计数