zoukankan      html  css  js  c++  java
  • 「SDOI2017」树点涂色(LCT+线段树)

    「SDOI2017」树点涂色(LCT+线段树)

    可以发现更新操作就是( ext{LCT})( ext{Access})操作,这个操作复杂度是(O(nlog n))

    因此,考虑对于每次的( ext{Access})操作,维护每个点到根的路径上不同的权值个数

    每次( ext{Access})操作只设计到合并两个链/断开一条链两种操作,可以通过线段树维护子树修改

    那么修改的复杂度就是(O(nlog^2 n))

    对于二操作,自己模拟一下就知道,就是两个点的答案-2(cdot ext{LCA})答案+1

    实现上有一些细节,就是更新的子树根节点是需要查询得到的

    const int N=1e5+10;
    
    int n,m;
    vector <int> G[N];
    int L[N],R[N],dfn;
    int son[N][2],fa[N],tfa[N][18],dep[N],id[N];
    int s[N<<2],t[N<<2],mi[N];
    
    void Upd(int p,int l,int r,int ql,int qr,int x) {
    	if(ql<=l && r<=qr) {
    		t[p]+=x;
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(ql<=mid) Upd(p<<1,l,mid,ql,qr,x);
    	if(qr>mid) Upd(p<<1|1,mid+1,r,ql,qr,x);
    	s[p]=max(t[p<<1]+s[p<<1],t[p<<1|1]+s[p<<1|1]);
    }
    int Que(int p,int l,int r,int ql,int qr) {
    	if(ql<=l && r<=qr) return s[p]+t[p];
    	int mid=(l+r)>>1,res=-1e9;
    	if(ql<=mid) cmax(res,Que(p<<1,l,mid,ql,qr));
    	if(qr>mid) cmax(res,Que(p<<1|1,mid+1,r,ql,qr));
    	return res+t[p];
    }
    int Que(int p,int l,int r,int x) {
    	int res=0;
    	while(1) {
    		if(l==r) return res+s[p]+t[p];
    		int mid=(l+r)>>1;
    		res+=t[p];
    		if(x<=mid) p<<=1,r=mid;
    		else p=p<<1|1,l=mid+1;
    	}
    }
    void Build(int p,int l,int r) {
    	if(l==r) { s[p]=dep[id[l]]+1; return; }
    	int mid=(l+r)>>1;
    	Build(p<<1,l,mid),Build(p<<1|1,mid+1,r);
    	s[p]=max(s[p<<1],s[p<<1|1]);
    }
    
    int dir(int x){ return son[fa[x]][1]==x; }
    int isroot(int x){ return !fa[x] || (son[fa[x]][0]!=x && son[fa[x]][1]!=x); } 
    void Up(int p) { mi[p]=son[p][0]?mi[son[p][0]]:p; }
    void rotate(int u) {
    	int f=fa[u],ff=fa[f],d=dir(u);
    	fa[u]=ff; if(!isroot(f)) son[ff][dir(f)]=u;
    	son[f][d]=son[u][!d]; if(son[u][!d]) fa[son[u][!d]]=f;
    	son[u][!d]=f,fa[f]=u; Up(f),Up(u);
    }
    void Splay(int x){ for(;!isroot(x);rotate(x)) if(!isroot(fa[x])) rotate((dir(x)^dir(fa[x]))?x:fa[x]); }
    void Access(int x) {
    	for(int t=0,y;x;t=x,x=fa[x]) {
    		Splay(x),y=son[x][1];
    		if(y) Upd(1,1,n,L[mi[y]],R[mi[y]],1);
    		if(t) Upd(1,1,n,L[mi[t]],R[mi[t]],-1);
    		son[x][1]=t,Up(x);
    	}
    } // LCT模板
    
    void dfs(int u,int f) {
    	mi[u]=u,fa[u]=tfa[u][0]=f,id[L[u]=++dfn]=u;
    	for(int i=1;(1<<i)<=dep[u];++i) tfa[u][i]=tfa[tfa[u][i-1]][i-1];
    	for(int v:G[u]) if(v!=f) dep[v]=dep[u]+1,dfs(v,u);
    	R[u]=dfn;
    }
    int LCA(int x,int y) {
    	if(dep[x]<dep[y]) swap(x,y);
    	for(int i=0,del=dep[x]-dep[y];(1<<i)<=del;++i) if(del&(1<<i)) x=tfa[x][i];
    	if(x==y) return x;
    	drep(i,17,0) if(tfa[x][i]!=tfa[y][i]) x=tfa[x][i],y=tfa[y][i];
    	return tfa[x][0];
    }
    
    int main(){
    	n=rd(),m=rd();
    	rep(i,2,n) {
    		int u=rd(),v=rd();
    		G[u].pb(v),G[v].pb(u);
    	}
    	dfs(1,0),Build(1,1,n);
    	rep(i,1,m) {
    		int opt=rd();
    		if(opt==1) Access(rd());
    		else if(opt==2) {
    			int x=rd(),y=rd(),z=LCA(x,y);
    			printf("%d
    ",Que(1,1,n,L[x])+Que(1,1,n,L[y])-2*Que(1,1,n,L[z])+1);
    		} else {
    			int x=rd();
    			printf("%d
    ",Que(1,1,n,L[x],R[x]));
    		}
    	}
    }
    
    
    
    
  • 相关阅读:
    滚动加载图片
    轮播图
    各种插件
    IE兼容
    文字换行
    CSS3 transform用法
    隐藏手机号中间几位数
    js实现收藏,首页等功能
    loading练习
    animation练习
  • 原文地址:https://www.cnblogs.com/chasedeath/p/13033040.html
Copyright © 2011-2022 走看看