zoukankan      html  css  js  c++  java
  • [SDOI2017]树点涂色

    XVII.[SDOI2017]树点涂色

    树剖和LCT学到最后实际上是殊途同归的……就比如说这题,可以用树剖,但是在操作\(1\)中借鉴了LCT的跳链思想;LCT则因为不能子树修改,按照dfs序需要建出线段树出来,实际上也就是树剖的思想了。

    首先讲一下LCT写法。观察到任意时刻,任意一种颜色一定是一条深度递增的链。那么刚好可以被存入LCT的一颗splay中。

    因此操作\(1\)就是直接access(x)即可。

    关于操作\(2\),我们可以采用树上差分的思想。观察到答案具有可减性。我们设\(res_x\)表示节点\(x\)到根的路径上颜色段数,则路径\((x,y)\)的答案即为\(res_x+res_y-res_{LCA_{x,y}}+1\),其中\(+1\)是因为\(LCA_{x,y}\)所在的那段颜色被减了两遍。

    操作\(3\)维护dfs序线段树直接求子树\(res\)最值即可(类似于树剖操作)。

    至于如何维护\(res\)的值呢?我们思考一下,发现它就是你把它access时,所经过的splay的数量。老办法,考虑虚子树的信息。我们只有在access时才会更改虚子树的关系。

    我们回忆一下access时我们干了点什么:

    inline void access(int x){
    	for(register int y=0;x;x=t[y=x].fa)splay(x),rson=y,pushup(x);
    }
    

    我们断掉rson的实边,并增加了y的实边。

    对于y,少了一个splay,应该整棵子树\(-1\);对于rson,多了一个splay,应该整棵子树\(+1\)

    但是!!!别忘了,splay中一切父子关系都是不可靠的。我们必须找到真正的rson和真正的y。而真正的rson和真正的y,就是以它们为根的splay中,深度最浅的点。

    然后我们写出了这样的找根函数:

    inline int find(int x){
    	pushdown(x);
    	while(lson)pushdown(x),x=lson;
    	return x;
    }
    

    使用这个就能找到正确的子节点。

    正确的access

    inline void access(int x){
    	for(register int y=0,z;x;x=t[y=x].fa){
    		splay(x);
    		if(rson)z=find(rson),modify(1,1,n,dfn[z],dfn[z]+sz[z]-1,1);
    		rson=y;
    		if(y)z=find(y),modify(1,1,n,dfn[z],dfn[z]+sz[z]-1,-1);
    		pushup(x);
    	}
    }
    

    总代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    //---------------------------------------------------------
    struct Edge{
    	int to,next;
    }edge[200100];
    struct SegTree{
    	int tag,mx;
    }seg[400100];
    struct LCT{
    	int fa,ch[2];
    	bool rev;
    }t[100100];
    //---------------------------------------------------------
    int head[100100],cnt,sz[100100];
    void ae(int u,int v){
    	edge[cnt].next=head[u],edge[cnt].to=v,head[u]=cnt++;
    	edge[cnt].next=head[v],edge[cnt].to=u,head[v]=cnt++;
    }
    //---------------------------------------------------------
    int dfn[100100],dep[100100],tot,rev[100100];
    int anc[100100][18];
    void dfs(int x,int fa){
    	dep[x]=dep[fa]+1,dfn[x]=++tot,t[x].fa=fa,sz[x]=1,rev[tot]=x,anc[x][0]=fa;
    	for(int i=1;(1<<i)<dep[x];i++)anc[x][i]=anc[anc[x][i-1]][i-1];
    	for(int i=head[x];i!=-1;i=edge[i].next)if(edge[i].to!=fa)dfs(edge[i].to,x),sz[x]+=sz[edge[i].to];
    }
    int LCA(int u,int v){
    	if(dep[u]>dep[v])swap(u,v);
    	for(int i=17;i>=0;i--)if(dep[u]<=dep[v]-(1<<i))v=anc[v][i];
    	if(u==v)return u;
    	for(int i=17;i>=0;i--)if(anc[u][i]!=anc[v][i])u=anc[u][i],v=anc[v][i];
    	return anc[u][0];
    }
    //---------------------------------------------------------
    #define lson x<<1
    #define rson x<<1|1
    #define mid ((l+r)>>1)
    void update(int x){seg[x].mx=max(seg[lson].mx,seg[rson].mx);}
    void ADD(int x,int y){seg[x].tag+=y,seg[x].mx+=y;}
    void downdate(int x){ADD(lson,seg[x].tag),ADD(rson,seg[x].tag),seg[x].tag=0;}
    void build(int x,int l,int r){
    	if(l==r){seg[x].mx=dep[rev[l]];return;}
    	build(lson,l,mid),build(rson,mid+1,r),update(x);
    }
    void modify(int x,int l,int r,int L,int R,int val){
    	if(l>R||r<L)return;
    	if(L<=l&&r<=R){ADD(x,val);return;}
    	downdate(x),modify(lson,l,mid,L,R,val),modify(rson,mid+1,r,L,R,val),update(x);
    }
    int query(int x,int l,int r,int L,int R){
    	if(l>R||r<L)return 0;
    	if(L<=l&&r<=R)return seg[x].mx;
    	downdate(x);
    	return max(query(lson,l,mid,L,R),query(rson,mid+1,r,L,R));
    }
    #undef lson
    #undef rson
    //---------------------------------------------------------
    #define lson t[x].ch[0]
    #define rson t[x].ch[1]
    inline int identify(int x){
    	if(x==t[t[x].fa].ch[0])return 0;
    	if(x==t[t[x].fa].ch[1])return 1;
    	return -1;
    }
    inline void pushup(int x){}
    inline void REV(int x){t[x].rev^=1,swap(lson,rson);}
    inline void pushdown(int x){
    	if(!t[x].rev)return;
    	if(lson)REV(lson);
    	if(rson)REV(rson);
    	t[x].rev=0;
    }
    inline void rotate(int x){
    	register int y=t[x].fa;
    	register int z=t[y].fa;
    	register int dirx=identify(x);
    	register int diry=identify(y);
    	register int b=t[x].ch[!dirx];
    	if(diry!=-1)t[z].ch[diry]=x;t[x].fa=z;
    	if(b)t[b].fa=y;t[y].ch[dirx]=b;
    	t[y].fa=x,t[x].ch[!dirx]=y;
    	pushup(y),pushup(x);
    }
    inline void pushall(int x){if(identify(x)!=-1)pushall(t[x].fa);pushdown(x);}
    inline void splay(int x){
    	pushall(x);
    	while(identify(x)!=-1){
    		register int fa=t[x].fa;
    		if(identify(fa)==-1)rotate(x);
    		else if(identify(x)==identify(fa))rotate(fa),rotate(x);
    		else rotate(x),rotate(x);
    	}
    }
    inline int find(int x){
    	pushdown(x);
    	while(lson)pushdown(x),x=lson;
    	return x;
    }
    inline void access(int x){
    	for(register int y=0,z;x;x=t[y=x].fa){
    		splay(x);
    		if(rson)z=find(rson),modify(1,1,n,dfn[z],dfn[z]+sz[z]-1,1);
    		rson=y;
    		if(y)z=find(y),modify(1,1,n,dfn[z],dfn[z]+sz[z]-1,-1);
    		pushup(x);
    	}
    }
    #undef lson
    #undef rson
    //---------------------------------------------------------
    int main(){
    	scanf("%d%d",&n,&m),memset(head,-1,sizeof(head));
    	for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),ae(x,y);
    	dfs(1,0),build(1,1,n);
    	for(int i=1,t1,t2,t3;i<=m;i++){
    		scanf("%d%d",&t1,&t2);
    		if(t1==1)access(t2);
    		if(t1==2){
    			scanf("%d",&t3);
    			int lca=LCA(t2,t3);
    			lca=query(1,1,n,dfn[lca],dfn[lca]);
    			t2=query(1,1,n,dfn[t2],dfn[t2]);
    			t3=query(1,1,n,dfn[t3],dfn[t3]);
    			printf("%d\n",t2+t3-2*lca+1);
    		}
    		if(t1==3)printf("%d\n",query(1,1,n,dfn[t2],dfn[t2]+sz[t2]-1));
    	}
    	return 0;
    }
    

  • 相关阅读:
    Codeforces 1045C Hyperspace Highways (看题解) 圆方树
    Codeforces 316E3 线段树 + 斐波那切数列 (看题解)
    Codeforces 803G Periodic RMQ Problem 线段树
    Codeforces 420D Cup Trick 平衡树
    Codeforces 295E Yaroslav and Points 线段树
    Codeforces 196E Opening Portals MST (看题解)
    Codeforces 653F Paper task SA
    Codeforces 542A Place Your Ad Here
    python基础 异常与返回
    mongodb 删除
  • 原文地址:https://www.cnblogs.com/Troverld/p/14602098.html
Copyright © 2011-2022 走看看