zoukankan      html  css  js  c++  java
  • [Sdoi2017]树点涂色 [lct 线段树]

    [Sdoi2017]树点涂色

    题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值


    考场发现这个信息是可减的,但是没想到lct

    特意设计成lct的形式!

    如何求颜色数?

    维护一个点和父亲的颜色是否一样,不一样为1,就是前缀和。考虑相邻的思想和那道“水位线”有点像

    x到y的答案就是(S_x + S_y - 2*S_{lca} + 1)

    一个点到根染新颜色,对应了lct的access操作,重边就是一样轻边就是不一样,修改轻重边就是子树加,其他两个操作单点求值,子树求最大值。用线段树维护dfs序

    实现上注意:

    • access过程中,不能直接修改rc和y,因为splay的形态是不断变化的,应该修改它们所在的splay代表的原树的根
    • 并且要先把rc与x重边切断再找根
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    using namespace std;
    const int N=1e5+5;
    #define fir first
    #define sec second
    inline int read() {
    	char c=getchar(); int x=0, f=1;
    	while(c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
    	while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
    	return x*f;
    }
    
    int n, Q, op, x, y;
    struct edge{int v, ne;} e[N<<1];
    int cnt=1, h[N];
    inline void ins(int u, int v) {
    	e[++cnt]=(edge){v, h[u]}; h[u]=cnt;
    	e[++cnt]=(edge){u, h[v]}; h[v]=cnt;
    }
    int fa[N], deep[N], size[N], mx[N], top[N], dfc, ver[N];
    pair<int, int> dfn[N];
    void dfs(int u) {
    	size[u]=1;
    	for(int i=h[u];i;i=e[i].ne)
    		if(e[i].v != fa[u]) {
    			int v=e[i].v;
    			fa[v] = u; deep[v] = deep[u]+1;
    			dfs(v);
    			size[u] += size[v];
    			if(size[v] > size[mx[u]]) mx[u] = v;
    		}
    }
    void dfs(int u, int anc) {
    	dfn[u].fir = ++dfc; ver[dfc] = u;
    	top[u] = anc;
    	if(mx[u]) dfs(mx[u], anc);
    	for(int i=h[u];i;i=e[i].ne) 
    		if(e[i].v != fa[u] && e[i].v != mx[u]) dfs(e[i].v, e[i].v);
    	dfn[u].sec = dfc;
    }
    inline int lca(int x, int y) {
    	while(top[x] != top[y]) {
    		if(deep[top[x]] < deep[top[y]]) swap(x, y);
    		x = fa[top[x]];
    	}
    	return deep[x] < deep[y] ? x : y;
    }
    
    namespace seg {
    #define mid ((l+r)>>1)
    #define lc x<<1
    #define rc x<<1|1
    #define lson lc, l, mid
    #define rson rc, mid+1, r
    	struct meow{int tag, max;} t[N<<2];
    	inline void paint(int x, int v) {
    		t[x].tag += v; t[x].max += v;
    	}
    	inline void pushdn(int x) {
    		if(t[x].tag) {
    			paint(lc, t[x].tag);
    			paint(rc, t[x].tag);
    			t[x].tag = 0;
    		}
    	}
    	inline void merge(int x) {t[x].max = max(t[lc].max, t[rc].max);}
    	void build(int x, int l, int r) {
    		if(l == r) t[x].max = deep[ ver[l] ] + 1;
    		else build(lson), build(rson), merge(x);
    	}
    	void add(int x, int l, int r, int ql, int qr, int v) {
    		if(ql<=l && r<=qr) paint(x, v);
    		else {
    			pushdn(x);
    			if(ql <= mid) add(lson, ql, qr, v);
    			if(mid < qr ) add(rson, ql, qr, v);
    			merge(x);
    		}
    	}
    	int que(int x, int l, int r, int p) {
    		if(l == r) return t[x].max;
    		else {
    			pushdn(x);
    			if(p <= mid) return que(lson, p);
    			else return que(rson, p);
    		}
    	}
    	int que(int x, int l, int r, int ql, int qr) {
    		if(ql<=l && r<=qr) return t[x].max;
    		else {
    			pushdn(x);
    			int ans=0;
    			if(ql <= mid) ans = max(ans, que(lson, ql, qr));
    			if(mid < qr ) ans = max(ans, que(rson, ql, qr));
    			return ans;
    		}
    	}
    
    #undef lc
    #undef rc
    }
    
    inline void addsub(int u, int val) { 
    	seg::add(1, 1, n, dfn[u].fir, dfn[u].sec, val); 
    }
    inline void quer(int x, int y) {
    	int p = lca(x, y); 
    	int ans = seg::que(1, 1, n, dfn[x].fir) + seg::que(1, 1, n, dfn[y].fir) - 2 * seg::que(1, 1, n, dfn[p].fir) + 1;
    	printf("%d
    ", ans);
    }
    inline void qmax(int x) { 
    	int ans = seg::que(1, 1, n, dfn[x].fir, dfn[x].sec);
    	printf("%d
    ", ans);
    }
    
    namespace lct {
    #define lc t[x].ch[0]
    #define rc t[x].ch[1]
    #define pa t[x].fa
    	struct meow{int ch[2], fa;} t[N];
    	int sz;
    	inline int wh(int x) {return t[pa].ch[1] == x;}
    	inline int isr(int x) {return t[pa].ch[0] != x && t[pa].ch[1] != x;}
    	inline void rotate(int x) {
    		int f=t[x].fa, g=t[f].fa, c=wh(x);
    		if(!isr(f)) t[g].ch[wh(f)] = x; t[x].fa = g;
    		t[f].ch[c] = t[x].ch[c^1]; t[ t[f].ch[c] ].fa = f;
    		t[x].ch[c^1] = f; t[f].fa = x;
    	}
    	inline void splay(int x) {
    		for(; !isr(x); rotate(x))
    			if(!isr(pa)) rotate(wh(x) == wh(pa) ? pa : x);
    	}
    	inline int findr(int x) {
    		splay(x); while(lc) x=lc; splay(x);
    		return x;
    	}
    	void access(int x) {
    		for(int y=0; x; y=x, x=pa) {
    			splay(x); 
    			if(rc) {
    				int u=rc; rc=0; 
    				u=findr(u), addsub(u, 1);
    			}
    			if(y) y=findr(y), addsub(y, -1);
    			rc=y;
    		}
    	}
    	void init() {for(int i=1; i<=n; i++) t[i].fa = fa[i];}
    }
    
    int main() {
    	//freopen("in", "r", stdin);
    	freopen("paint.in", "r", stdin);
    	freopen("paint.out", "w", stdout);
    	n=read(); Q=read();
    	for(int i=1; i<n; i++) ins(read(), read());
    	dfs(1); dfs(1, 1); seg::build(1, 1, n); lct::init();
    	//for(int i=1; i<=n; i++) printf("%d ", ver[i]); puts(" ver");
    	for(int i=1; i<=Q; i++) {
    		op=read(); x=read();
    		if(op==1) lct::access(x);
    		else if(op==2) y=read(), quer(x, y);
    		else qmax(x);
    	}
    }
    
    
  • 相关阅读:
    Android SDK
    1055
    清除浮动的三种方式
    解决块状元素垂直外边距的塌陷问题
    drf 验证接口权限
    Linux常用指令
    Linux安装python3,virtualenv和virtualenvwrapper
    Linux基本命令2
    Linux之文档与目录结构
    Linux基本命令
  • 原文地址:https://www.cnblogs.com/candy99/p/6699705.html
Copyright © 2011-2022 走看看