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

    Description

    Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路

    径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:

    1 x:

    把点x到根节点的路径上所有的点染上一种没有用过的新颜色。

    2 x y:

    求x到y的路径的权值。

    3 x

    在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。

    Bob一共会进行m次操作

    Input

    第一行两个数n,m。

    接下来n-1行,每行两个数a,b,表示a与b之间有一条边。

    接下来m行,表示操作,格式见题目描述

    1<=n,m<=100000

    Output

    每当出现2,3操作,输出一行。

    如果是2操作,输出一个数表示路径的权值

    如果是3操作,输出一个数表示权值的最大值

    Sample Input

    5 6
    1 2
    2 3
    3 4
    3 5
    2 4 5
    3 3
    1 4
    2 4 5
    1 5
    2 4 5
    

    Sample Output

    3
    4
    2
    2
    

    solution

    (LCT)好题。

    对于(1)操作,注意到每次都是从(x)到根的修改,而且每次颜色都不一样,可以类比于(LCT)(access)

    所以开一颗(LCT)(LCT)内每一颗(splay)维护一种颜色,然后改颜色直接(access)就好了。

    考虑怎么维护问的东西。

    注意到要同时维护链上信息和子树信息,可以考虑拿一个(dfs)序建的线段树来维护每个点到根节点路径的权值。

    然后每次(access)的时候,实边变虚边就把子树内所有权值(+1),反之(-1)

    然后对于(3)操作拿线段树记一下(max)就好了。

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 1e5+1;
    
    int fa[maxn],son[maxn][2],dfn[maxn],sz[maxn],head[maxn],tot,dfn_cnt,R[maxn],dep[maxn],n,m,f[maxn][20];
    struct edge {int to,nxt;}e[maxn<<1];
    
    void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    void ins(int u,int v) {add(u,v),add(v,u);}
    
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
    
    struct Segment_Tree {
    	int tr[maxn],tag[maxn];
    	void update(int p) {tr[p]=max(tr[ls],tr[rs]);}
    	void push_tag(int p,int v) {tr[p]+=v,tag[p]+=v;}
    	void pushdown(int p) {
    		if(!tag[p]) return ;
    		tr[ls]+=tag[p],tr[rs]+=tag[p],tag[ls]+=tag[p],tag[rs]+=tag[p];
    		tag[p]=0;
    	}
    	void modify(int p,int l,int r,int x,int y,int v) {
    		if(x<=l&&r<=y) return tr[p]+=v,tag[p]+=v,void();
    		pushdown(p);
    		if(x<=mid) modify(ls,l,mid,x,y,v);
    		if(y>mid) modify(rs,mid+1,r,x,y,v);
    		update(p);
    	}
    	int query(int p,int l,int r,int x,int y) {
    		if(x<=l&&r<=y) return tr[p];
    		int ans=0;pushdown(p);
    		if(x<=mid) ans=max(ans,query(ls,l,mid,x,y));
    		if(y>mid) ans=max(ans,query(rs,mid+1,r,x,y));
    		return ans;
    	}
    	void build(int p,int l,int r) {
    		if(l==r) return tr[p]=dep[R[l]],void();
    		build(ls,l,mid),build(rs,mid+1,r);
    		update(p);
    	}
    }SGT;
    
    #undef ls
    #undef rs
    #undef mid 
    
    struct Input_Tree {
    	void dfs(int x,int F) {
    		fa[x]=F,sz[x]=1,dfn[x]=++dfn_cnt,R[dfn_cnt]=x,f[x][0]=F,dep[x]=dep[F]+1;
    		for(int i=1;i<=19;i++) f[x][i]=f[f[x][i-1]][i-1];
    		for(int i=head[x];i;i=e[i].nxt)
    			if(e[i].to!=F) dfs(e[i].to,x),sz[x]+=sz[e[i].to];
    	}
    	int lca(int x,int y) {
    		if(dep[x]<dep[y]) swap(x,y);
    		for(int i=19;~i;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
    		if(x==y) return x;
    		for(int i=19;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    		return f[x][0];
    	}
    }T;
    
    struct Link_Cut_Tree {
    	int is_root(int x) {return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
    	int which(int x) {return son[fa[x]][1]==x;}
    	void rotate(int x) {
    		int F=fa[x],ff=fa[F],w=which(x);
    		if(!is_root(F)) son[ff][son[ff][1]==F]=x;
    		fa[x]=ff,fa[F]=x,fa[son[x][w^1]]=F,son[F][w]=son[x][w^1],son[x][w^1]=F;
    	}
    	void splay(int x) {
    		while(!is_root(x)) {
    			int y=fa[x],z=fa[y];
    			if(!is_root(y)) rotate(((son[y][1]==x)^(son[z][1]==y))?x:y);
    			rotate(x);
    		}
    	}
    	int pre(int x) {
    		while(son[x][0]) x=son[x][0];
    		return x;
    	}
    	void access(int x) {
    		for(int t=0;x;t=x,x=fa[x]) {
    			splay(x);
    			if(son[x][1]) {
    				int p=pre(son[x][1]);
    				SGT.modify(1,1,n,dfn[p],dfn[p]+sz[p]-1,1);
    			}
    			son[x][1]=t;
    			if(t) {
    				int p=pre(t);
    				SGT.modify(1,1,n,dfn[p],dfn[p]+sz[p]-1,-1);
    			}
    		}
    	}
    }LCT;
    
    int main() {
    	read(n),read(m);
    	for(int i=1,x,y;i<n;i++) read(x),read(y),ins(x,y);
    	T.dfs(1,0);SGT.build(1,1,n);
    	for(int op,x,y,i=1;i<=m;i++) {
    		read(op),read(x);
    		if(op==1) LCT.access(x);
    		else if(op==2) {
    			read(y);int ans=1,tmp=dfn[T.lca(x,y)];
    			ans+=SGT.query(1,1,n,dfn[x],dfn[x])+SGT.query(1,1,n,dfn[y],dfn[y]);
    			ans-=2*SGT.query(1,1,n,tmp,tmp);write(ans);
    		} else write(SGT.query(1,1,n,dfn[x],dfn[x]+sz[x]-1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    MySQL distinct 与 group by 去重(where/having)
    mysql 的垂直分表和水平分表
    查看mysql语句运行时间
    PHP的性能优化方法总结
    Apache ab 压测工具使用说明
    LNMP 性能优化之 PHP 性能优化
    [PHP]日志处理error_log()函数和配置使用
    cocos2dx之tolua++全面分析(二):类注册
    在命令行上启动genymotion虚拟机
    在64位ubuntu上安装alienbrain客户端
  • 原文地址:https://www.cnblogs.com/hbyer/p/10144357.html
Copyright © 2011-2022 走看看