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

    Luogu P3703 [SDOI2017]树点涂色
    用LCT中每一个Splay维护颜色相同的点集,则从一个点到根节点的轻边的条数就是这个点的到根的权值。至于路径查询的搞个差分就好,用树剖实现。
    至于为什么可以直接这样查,是因为LCT里面涉及子树的权值变化只有access函数。在splay中的子树的切换是属于实链中的变化,对权值没有影响。
    所以这题其实就是个裸树剖+LCT

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    #define R register
    #define LL long long
    const int inf = 0x3f3f3f3f;
    const int MAXN = 1e5 + 10;
    
    inline int read() {
    	char a = getchar(); int x = 0,f = 1;
    	for(; a > '9' || a < '0'; a = getchar()) if(a == '-') f = -1;
    	for(; a >= '0' && a <= '9' ;a = getchar()) x = x * 10 + a - '0';
    	return x * f;
    }
    
    namespace Data {
    	class SegTree {
    		#define ls(x) (x<<1)
    		#define rs(x) (x<<1|1)
    		private: 
    			int tg[MAXN<<2],mx[MAXN<<2];
    			inline void update(int x) { mx[x]=max(mx[ls(x)], mx[rs(x)]); }
    			inline void get(int x,int k) { tg[x]+=k; mx[x]+=k; }
    			inline void pushdown(int x) {
    				if(tg[x]) {
    					if(ls(x)) get(ls(x),tg[x]);
    					if(rs(x)) get(rs(x),tg[x]);
    					tg[x]=0;
    				}
    			}
    		public:
    			inline void add(int x,int l,int r,int Le,int Ri,int k) {
    				if(Le<=l&&r<=Ri) { get(x,k); return ;}
    				pushdown(x);
    				int mid=l+r;mid>>=1;
    				if(Le<=mid) add(ls(x),l,mid,Le,Ri,k);
    				if(Ri>mid) add(rs(x),mid+1,r,Le,Ri,k);
    				update(x);
    			}
    			inline int ask(int x,int l,int r,int Le,int Ri) {
    				if(Le<=l&&r<=Ri) return mx[x];
    				pushdown(x);
    				int mid=l+r;mid>>=1;
    				int ans=-inf;
    				if(Le<=mid) ans=max(ans,ask(ls(x),l,mid,Le,Ri));
    				if(Ri>mid) ans=max(ans,ask(rs(x),mid+1,r,Le,Ri));
    				update(x);
    				return ans;
    			}
    		#undef ls
    		#undef rs
    	};
    }
    
    using Data::SegTree;
    
    namespace Graph {
    	struct Edge { int to,next; } e[MAXN<<1];
    	int head[MAXN],cnt;
    	inline void add(int x,int y) { e[++cnt]={y,head[x]}; head[x]=cnt; }
    	int dep[MAXN],fa[MAXN],siz[MAXN],son[MAXN],top[MAXN],dfn[MAXN],tot;
    	inline void dfs1(int x,int fx) {
    		dep[x]=dep[fx]+1; fa[x]=fx; siz[x]=1; dfn[x]=++tot;
    		for(R int i=head[x];i;i=e[i].next) {
    			int y=e[i].to;
    			if(y==fx) continue;
    			dfs1(y,x);
    			siz[x]+=siz[y];
    			if(siz[y]>siz[son[x]]) son[x]=y;
    		}
    	}
    	inline void dfs2(int x,int topx) {
    		top[x]=topx;
    		if(son[x]) dfs2(son[x],topx);
    		for(R int i=head[x];i;i=e[i].next) {
    			int y=e[i].to;
    			if(y==fa[x]||y==son[x]) continue;
    			dfs2(y,y);
    		}
    	}
    	inline int lca(int x,int y) {
    		while(top[x]!=top[y])
    			if(dep[top[x]]>dep[top[y]]) 
    				x=fa[top[x]];
    			else
    				y=fa[top[y]];
    		return dep[x]<dep[y]?x:y;
    	}
    	inline void build() { dfs1(1,0); dfs2(1,1); }
    }
    
    using Graph::dfn;
    using Graph::lca;
    using Graph::build;
    using Graph::add;
    using Graph::siz;
    using Graph::dep;
    using Graph::head;
    using Graph::e;
    
    int n,m;
    SegTree ST;
    namespace Link_Cut_Tree {
    	class LCT {
    		#define ls(x) ch[x][0]
    		#define rs(x) ch[x][1]
    		private:
    			int fa[MAXN],ch[MAXN][2];
    		public:
    			inline int nroot(int x) { return rs(fa[x])==x||ls(fa[x])==x; }
    			inline int get(int x) { return rs(fa[x])==x; }
    			inline void rotate(int x) {
    				int y=fa[x],z=fa[y],k=get(x),w=ch[x][!k];
    				if(nroot(y)) ch[z][get(y)]=x; ch[x][!k]=y; ch[y][k]=w;
    				if(w) fa[w]=y; fa[y]=x; fa[x]=z;
    			}
    			inline void splay(int x) {
    				while(nroot(x)) {
    					if(nroot(fa[x]))
    						rotate(get(x)^get(fa[x])?x:fa[x]);
    					rotate(x);				
    				}	
    			}
    			inline int findrt(int x) {
    				while(ls(x)) x=ls(x); return x;
    			}
    			inline void access(int x) {
    				for(R int y=0;x;x=fa[y=x]) {
    					splay(x);
    					if(rs(x)) {
    						int rt=findrt(rs(x));
    						ST.add(1,1,n,dfn[rt],dfn[rt]+siz[rt]-1,1);
    					}
    					if(y) {
    						int rt=findrt(y);
    						ST.add(1,1,n,dfn[rt],dfn[rt]+siz[rt]-1,-1);
    					}
    					rs(x)=y;
    				}
    			}
    			inline void build(int x,int fx) {
    				fa[x]=fx;
    				for(R int i=head[x];i;i=e[i].next) {
    					int y=e[i].to;
    					if(y==fx) continue;
    					build(y,x);
    				}
    			}
    		#undef ls
    		#undef rs
    	};
    }
    
    using Link_Cut_Tree::LCT;
    
    LCT T;
    
    int main() {
    	n=read(); m=read();
    	for(R int i=1;i<n;i++) {
    		int x=read(),y=read();
    		add(x,y); add(y,x);	
    	}
    	build();T.build(1,0);
    	for(R int i=1;i<=n;i++) ST.add(1,1,n,dfn[i],dfn[i],dep[i]);
    	while(m--) {
    		int op=read(),x=read(),y;
    		if(op==2) y=read();
    		if(op==1) T.access(x);
    		if(op==2) {
    			int Lca=lca(x,y);
    			int s1=ST.ask(1,1,n,dfn[x],dfn[x]);
    			int s2=ST.ask(1,1,n,dfn[y],dfn[y]);
    			int s3=ST.ask(1,1,n,dfn[Lca],dfn[Lca]);
    			printf("%d
    ",s1+s2-s3*2+1);
    		}
    		if(op==3) {
    			int s=ST.ask(1,1,n,dfn[x],dfn[x]+siz[x]-1);
    			printf("%d
    ",s);
    		}
    	}
    	return 0;	
    }
    
  • 相关阅读:
    requirejs实现对动态combo的支持
    遇见Javascript类型数组(Typed Array)
    【转发】2012年HTML5的14个大胆预言
    跟我学canvas(三,应用图像)
    贡献一个连jquery都觉的大的时候可以用的 js库
    websocket终成标准
    Django中的form不足之处
    Eclipse+Pydev 开发Django中的Debug模式
    Javascript中指定周末日期的计算
    Python中递归的最大次数
  • 原文地址:https://www.cnblogs.com/clover4/p/12883696.html
Copyright © 2011-2022 走看看