zoukankan      html  css  js  c++  java
  • bzoj 4817: [Sdoi2017]树点涂色 LCT+树链剖分+线段树

    题目:

    Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同.
    定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。
    Bob可能会进行这几种操作:
    1 x: 把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
    2 x y: 求x到y的路径的权值。
    3 x y: 在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
    1<=n,m<=100000

    题解:

    这道题就是重组病毒的弱化版.
    要是HE省选也考这种我会的题目超级弱化版就好了
    跟重组病毒一样,我们发现第一个操作其实就是把一条链到根的颜色变得相同了.
    如果我们用一条连向fa的虚边表示这个点的颜色和父亲的节点的颜色不同
    反之,实边表示相同.那么如果求两点路径权值就是求路径上虚边的个数+1(因lca未被统计)
    然后我们发现第一个操作其实就是Access.
    然后外部进行树链剖分,在LCT Access的切断和连接实边的时候更新外部数据结构即可.
    2,3两个操作都可以分别维护.
    对于操作2 : 若某点连向fa为虚边对单点赋值为1,否则为0.然后直接跳top统计即可.
    对于操作3 : 对每个点维护一个这个点到根的路径权,每次若连向fa的边改变,做区间修改即可,查询即区间最值.

    代码比重组病毒好写多了

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    inline void read(int &x){
    	x=0;static char ch;static bool flag;flag = false;
    	while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    	while(x=(x<<1)+(x<<3)+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
    }
    #define rg register int
    #define rep(i,a,b) for(rg i=(a);i<=(b);++i)
    #define per(i,a,b) for(rg i=(a);i>=(b);--i)
    const int maxn = 100010;
    struct Edge{
    	int to,next;
    }G[maxn<<1];
    int head[maxn],cnt;
    void add(int u,int v){
    	G[++cnt].to = v;
    	G[cnt].next = head[u];
    	head[u] = cnt;
    }
    int n,m;
    namespace seg{
    #define v G[i].to
    	int top[maxn],son[maxn],siz[maxn];
    	int dep[maxn],ind[maxn],oud[maxn];
    	int dfs_clock,fa[maxn];
    	void dfs(int u){
    		siz[u] = 1;
    		for(int i = head[u];i;i=G[i].next){
    			if(v == fa[u]) continue;
    			fa[v] = u;
    			dep[v] = dep[u] + 1;
    			dfs(v);
    			siz[u] += siz[v];
    			if(siz[son[u]] < siz[v]) son[u] = v;
    		}
    	}
    	void dfs(int u,int tp){
    		top[u] = tp;
    		ind[u] = ++ dfs_clock;
    		if(son[u]) dfs(son[u],tp);
    		for(int i = head[u];i;i=G[i].next){
    			if(v == fa[u] || v == son[u]) continue;
    			dfs(v,v);
    		}
    		oud[u] = dfs_clock;
    	}
    #undef v
    	struct segTree{
    		int sum[maxn<<2],tag[maxn<<2],mx[maxn<<2];
    		inline void pushdown(int rt,int l,int r){
    			if(rt == 0 || tag[rt] == 0) return ;
    			int mid = l+r >> 1;
    			sum[rt<<1] += tag[rt]*(mid - l + 1);
    			sum[rt<<1|1] += tag[rt]*(r - mid);
    			mx[rt<<1] += tag[rt];
    			mx[rt<<1|1] += tag[rt];
    			tag[rt<<1] += tag[rt];
    			tag[rt<<1|1] += tag[rt];
    			tag[rt] = 0;
    		}
    		void modify(int rt,int l,int r,int L,int R,int d){
    			if(L <= l && r <= R){
    				tag[rt] += d;
    				sum[rt] += d*(r - l + 1);
    				mx[rt] += d;
    				return ;
    			}
    			int mid = l+r >> 1;pushdown(rt,l,r);
    			if(L <= mid) modify(rt<<1,l,mid,L,R,d);
    			if(R >  mid) modify(rt<<1|1,mid+1,r,L,R,d);
    			sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    			mx[rt] = max(mx[rt<<1],mx[rt<<1|1]);
    		}
    		int query_max(int rt,int l,int r,int L,int R){
    			if(L <= l && r <= R) return mx[rt];
    			int mid = l+r >> 1;pushdown(rt,l,r);
    			if(R <= mid) return query_max(rt<<1,l,mid,L,R);
    			if(L >  mid) return query_max(rt<<1|1,mid+1,r,L,R);
    			return max(query_max(rt<<1,l,mid,L,R),query_max(rt<<1|1,mid+1,r,L,R));
    		}
    		int query_sum(int rt,int l,int r,int L,int R){
    			if(L <= l && r <= R) return sum[rt];
    			int mid = l+r >> 1;pushdown(rt,l,r);
    			if(R <= mid) return query_sum(rt<<1,l,mid,L,R);
    			if(L >  mid) return query_sum(rt<<1|1,mid+1,r,L,R);
    			return query_sum(rt<<1,l,mid,L,R) + query_sum(rt<<1|1,mid+1,r,L,R);
    		}
    	}T1,T2;
    }
    namespace lct{
    	using namespace seg;
    	struct Node{
    		Node *ch[2],*fa;
    		int id;
    	}mem[maxn],*it,*null;
    	inline void init(){
    		it = mem;null = it++;
    		null->ch[0] = null->ch[1] = null->fa = null;
    		null->id = -1;
    	}
    	inline Node* newNode(){
    		Node *p = it++;
    		p->ch[0] = p->ch[1] = p->fa = null;
    		return p;
    	}
    	inline void rotate(Node *p,Node *x){
    		int k = p == x->ch[1];
    		Node *y = p->ch[k^1],*z = x->fa;
    		if(z->ch[0] == x) z->ch[0] = p;
    		if(z->ch[1] == x) z->ch[1] = p;
    		if(y != null) y->fa = x;
    		p->ch[k^1] = x;p->fa = z;
    		x->ch[k] = y;x->fa = p;
    	}
    	inline bool isroot(Node *p){
    		return (p == null) || (p->fa->ch[0] != p && p->fa->ch[1] != p);
    	}
    	inline void Splay(Node *p){
    		while(!isroot(p)){
    			Node *x = p->fa,*y = x->fa;
    			if(isroot(x)) rotate(p,x);
    			else if((p == x->ch[0])^(x == y->ch[0])) rotate(p,x),rotate(p,y);
    			else rotate(x,y),rotate(p,x);
    		}
    	}
    	inline void Access(Node *x){
    		for(Node *y = null;x != null;y = x,x = x->fa){
    			Splay(x);
    			Node *p = x->ch[1];
    			while(p->ch[0] != null) p = p->ch[0];
    			if(p != null){
    				T1.modify(1,1,n,ind[p->id],ind[p->id],1);
    				T2.modify(1,1,n,ind[p->id],oud[p->id],1);
    			}
    			p = y;
    			while(p->ch[0] != null) p = p->ch[0];
    			if(p != null){
    				T1.modify(1,1,n,ind[p->id],ind[p->id],-1);
    				T2.modify(1,1,n,ind[p->id],oud[p->id],-1);
    			}
    			x->ch[1] = y;
    		}
    	}
    }
    inline int query(int u,int v){
    	using namespace seg;
    	int ret = 0;
    	while(top[u] != top[v]){
    		if(dep[top[u]] < dep[top[v]]) swap(u,v);
    		ret += T1.query_sum(1,1,n,ind[top[u]],ind[u]);
    		u = fa[top[u]];
    	}if(dep[u] > dep[v]) swap(u,v);
    	if(ind[u] + 1 <= ind[v]) ret += T1.query_sum(1,1,n,ind[u]+1,ind[v]);
    	return ret;
    }
    int main(){
    	using namespace lct;
    	using namespace seg;
    	read(n);read(m);
    	init();
    	rep(i,1,n) newNode()->id = i;
    	rg u,v;
    	rep(i,1,n-1){
    		read(u);read(v);
    		add(u,v);add(v,u);
    	}
    	dfs(1);dfs(1,1);
    	rep(i,2,n){
    		T1.modify(1,1,n,ind[i],ind[i],1);
    		T2.modify(1,1,n,ind[i],oud[i],1);
    		(mem+i)->fa = (mem+fa[i]);
    	}
    	rg op;
    	while(m--){
    		read(op);
    		if(op == 1){
    			read(u);
    			Access(mem+u);
    		}else if(op == 2){
    			read(u);read(v);
    			printf("%d
    ",query(u,v)+1);
    		}else if(op == 3){
    			read(u);
    			printf("%d
    ",T2.query_max(1,1,n,ind[u],oud[u])+1);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    tomcat修改端口
    JSP_大并发_秒杀
    Nexus刷官方下载的映像_occam
    Nexus杂
    多项式ADT加法乘法——数组实现
    单链表——游标实现
    链表基本操作实现
    二叉查找树
    AVL树
    ORM框架疏理——廖雪峰实战系列(一)
  • 原文地址:https://www.cnblogs.com/Skyminer/p/6710875.html
Copyright © 2011-2022 走看看