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

    题目

    抄题解.jpg

    当是用来复习(LCT)的了

    发现一操作很具有灵性,把一个点到根的路径涂上一种新颜色,这里的新颜色竟然和之前的都不同,那么所有的颜色必然都会是一段深度连续的路径了

    既然是暴力到根,那么我们就会发现这个和(lct)(access)操作很像啊;而且每段颜色都是一段深度连续的路径,而一个(splay)里维护的也就是这些东西

    于是我们可以直接使用(lct)来维护第一问,直接(access)上去把这个点到根的路径都搞到一个(splay)中去,这样一个(splay)里维护的就是颜色相同的一段路径

    面对二操作,好像这是一个树剖操作啊,但是我们发现这里的同一颜色都是深度连续的,于是可以考虑使用树上差分,也就是(pre_x+pre_y-2 imes pre_{lca}+1)(+1)是因为(lca)被减了两次

    考虑在(access)的同时维护出这个东西

    回顾我们的(access)操作,板子里是这样写的

    for(int y=0;x;y=x,f=fa[x])
    	splay(x),ch[x][1]=y,pushup(x);
    

    发现我们就是不断重复断掉(x)和之前的深度比它大的点之间的关系,连上一个新的儿子

    断掉那个之前的深度更大的儿子,显然那个儿子就自己变成了一个(splay)的根了,这个(splay)以及下面的其余(splay)发现上面都出现了一个新的颜色,于是这个子树的(pre)都应该加(1)

    连上新的儿子,新的儿子原来的那棵(splay)就消失了了,和当前的(splay)合并在一起了,于是我们应该把这棵子树的答案减(1)

    于是我们(dfn)+线段树维护一下就好了

    三操作就是查一个子树最大值,没了

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define re register
    #define LL long long
    const int maxn=100005;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct E{int v,nxt;}e[maxn<<1];
    inline int max(int a,int b) {return a>b?a:b;}
    int ch[maxn][2],fa[maxn],f[maxn],deep[maxn],dfn[maxn],id[maxn];
    int head[maxn],son[maxn],sum[maxn],top[maxn];
    int l[maxn<<2],r[maxn<<2],tag[maxn<<2],mx[maxn<<2];
    int n,m,num,__;
    inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
    inline void pushup(int x) {mx[x]=max(mx[x<<1],mx[x<<1|1]);}
    void build(int x,int y,int i) {
    	l[i]=x,r[i]=y;
    	if(x==y) {mx[i]=deep[id[x]];return;}
    	int mid=x+y>>1;
    	build(x,mid,i<<1);build(mid+1,y,i<<1|1);
    	pushup(i);
    }
    inline void pushdown(int i) {
    	if(!tag[i]) return;
    	tag[i<<1]+=tag[i],tag[i<<1|1]+=tag[i];
    	mx[i<<1]+=tag[i];mx[i<<1|1]+=tag[i];
    	tag[i]=0;
    }
    void change(int x,int y,int i,int val) {
    	if(x<=l[i]&&y>=r[i]) {
    		mx[i]+=val;tag[i]+=val;
    		return;
    	}
    	pushdown(i);
    	int mid=l[i]+r[i]>>1;
    	if(x<=mid) change(x,y,i<<1,val);
    	if(y>mid) change(x,y,i<<1|1,val);
    	pushup(i);
    }
    int query(int x,int y,int i) {
    	if(x<=l[i]&&y>=r[i]) return mx[i];
    	pushdown(i);
    	int mid=l[i]+r[i]>>1,now=0;
    	if(x<=mid) now=max(now,query(x,y,i<<1));
    	if(y>mid) now=max(now,query(x,y,i<<1|1));
    	return now;
    }
    int ask(int pos,int i) {
    	if(l[i]==r[i]) return mx[i];
    	pushdown(i);
    	int mid=l[i]+r[i]>>1;
    	if(pos<=mid) return ask(pos,i<<1);
    	return ask(pos,i<<1|1); 
    }
    inline void Add(int x,int val) {change(dfn[x],dfn[x]+sum[x]-1,1,val);}
    inline int nroot(int x) {return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
    inline void rotate(int x) {
    	int y=fa[x],z=fa[y],k=ch[y][1]==x,w=ch[x][k^1];
    	if(nroot(y)) ch[z][ch[z][1]==y]=x;
    	ch[x][k^1]=y,ch[y][k]=w;
    	fa[w]=y,fa[y]=x,fa[x]=z;
    }
    inline void splay(int x) {
    	while(nroot(x)) {
    		int y=fa[x];
    		if(nroot(y)) rotate((ch[y][1]==x)^(ch[fa[y]][1]==y)?x:y);
    		rotate(x);
    	}
    }
    inline int frt(int x) {
    	while(ch[x][0]) x=ch[x][0];
    	return x;
    }
    inline void access(int x) {
    	for(re int y=0;x;y=x,x=fa[x]) {
    		splay(x);
    		if(ch[x][1]) Add(frt(ch[x][1]),1);
    		if(y) Add(frt(y),-1);
    		ch[x][1]=y;
    	}
    }
    void dfs1(int x) {
    	sum[x]=1;int maxx=-1;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(deep[e[i].v]) continue;
    		deep[e[i].v]=deep[x]+1;f[e[i].v]=fa[e[i].v]=x;
    		dfs1(e[i].v);sum[x]+=sum[e[i].v];
    		if(sum[e[i].v]>maxx) son[x]=e[i].v,maxx=sum[e[i].v];
    	}
    }
    void dfs2(int x,int topf) {
    	top[x]=topf;dfn[x]=++__,id[__]=x;
    	if(!son[x]) return;
    	dfs2(son[x],topf);
    	for(re int i=head[x];i;i=e[i].nxt)
    	if(!top[e[i].v]) dfs2(e[i].v,e[i].v);
    }
    inline int LCA(int x,int y) {
    	while(top[x]!=top[y]) {
    		if(deep[top[x]]<deep[top[y]]) std::swap(x,y);
    		x=f[top[x]];
    	}
    	if(deep[x]<deep[y]) return x;return y;
    }
    int main() {
    	n=read(),m=read();
    	for(re int x,y,i=1;i<n;i++)
    		x=read(),y=read(),add(x,y),add(y,x);
    	deep[1]=1,dfs1(1),dfs2(1,1),build(1,n,1);
    	int opt,x,y;
    	while(m--) {
    		opt=read(),x=read();
    		if(opt==1) access(x);
    		if(opt==2) 
    			y=read(),printf("%d
    ",ask(dfn[x],1)+ask(dfn[y],1)-2*ask(dfn[LCA(x,y)],1)+1);
    		if(opt==3) 
    			printf("%d
    ",query(dfn[x],dfn[x]+sum[x]-1,1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    【Tomcat】export: `xxx': 不是有效的标识符
    【Linux】查看程序是否正常运行
    【Linux】bat文件如何执行
    【oracle】截取字符串
    【java异常】Expected one result (or null) to be returned by selectOne(), but found: 63
    【java异常】定时任务异常ERROR 20604 --- [ scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task
    【oracle】ORA-12638
    【java异常】Unable to install breakpoint in
    【oracle】处理锁表
    20180318 代码错题(4)
  • 原文地址:https://www.cnblogs.com/asuldb/p/10617262.html
Copyright © 2011-2022 走看看