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

    [BZOJ4817][Sdoi2017]树点涂色

    试题描述

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

    输入

    第一行两个数n,m。
    接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
    接下来m行,表示操作,格式见题目描述
    1<=n,m<=100000

    输出

    每当出现2,3操作,输出一行。
    如果是2操作,输出一个数表示路径的权值
    如果是3操作,输出一个数表示权值的最大值

    输入示例

    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

    输出示例

    3
    4
    2
    2

    数据规模及约定

    见“输入

    题解

    操作 1 即为 LCT 里面的 access 操作;对于询问,我们只需要知道每个点到根的路径上有多少条虚边就好了(令节点 x 到根的路径上虚边条数为 tot[x]):操作 2,查询路径 (u, v) 的话就是 tot[u] + tot[v] - 2tot[lca(u,v)](lca(u, v) 即节点 u 和 v 的最近公共祖先);操作 3,就是查询一个子树内最大的 tot。

    所以可以用线段树维护 dfs 序,access 时删除或添加一条虚边对应子树集体 -1 或子树集体 +1(注意找 dfs 序中的区间时要找到 splay 中最靠左的节点,即深度最小的节点)。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define maxm 200010
    #define maxlog 17
    
    namespace TREE {
    	int n, m, head[maxn], nxt[maxm], to[maxm];
    	
    	void AddEdge(int a, int b) {
    		to[++m] = b; nxt[m] = head[a]; head[a] = m;
    		swap(a, b);
    		to[++m] = b; nxt[m] = head[a]; head[a] = m;
    		return ;
    	}
    	
    	int fa[maxn][maxlog], dep[maxn], dl[maxn], dr[maxn], uid[maxn], clo;
    	void build(int u) {
    		uid[dl[u] = ++clo] = u;
    		for(int i = 1; i < maxlog; i++) fa[u][i] = fa[fa[u][i-1]][i-1];
    		for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa[u][0]) {
    			fa[to[e]][0] = u;
    			dep[to[e]] = dep[u] + 1;
    			build(to[e]);
    		}
    		dr[u] = clo;
    		return ;
    	}
    	int lca(int a, int b) {
    		if(dep[a] < dep[b]) swap(a, b);
    		for(int i = maxlog - 1; i >= 0; i--) if(dep[a] - (1 << i) >= dep[b]) a = fa[a][i];
    		for(int i = maxlog - 1; i >= 0; i--) if(fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i];
    		return a == b ? a : fa[b][0];
    	}
    }
    using namespace TREE;
    
    struct SEG {
    	int maxv[maxn<<2], addv[maxn<<2];
    	
    	SEG() { memset(addv, 0, sizeof(addv)); }
    	
    	void build(int o, int l, int r) {
    		if(l == r) maxv[o] = dep[uid[l]]; //, printf("%d -> %d: %d
    ", l, uid[l], maxv[o]);
    		else {
    			int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    			build(lc, l, mid); build(rc, mid + 1, r);
    			maxv[o] = max(maxv[lc], maxv[rc]);
    		}
    		return ;
    	}
    	
    	void pushdown(int o, int l, int r) {
    		if(!addv[o]) return ;
    		if(l == r){ addv[o] = 0; return ; }
    		int lc = o << 1, rc = lc | 1;
    		addv[lc] += addv[o]; addv[rc] += addv[o];
    		maxv[lc] += addv[o]; maxv[rc] += addv[o];
    		addv[o] = 0;
    		return ;
    	}
    	void update(int o, int l, int r, int ql, int qr, int v) {
    		if(ql > qr || !ql || !qr) return ;
    		pushdown(o, l, r);
    		if(ql <= l && r <= qr) {
    			addv[o] += v; maxv[o] += v;
    			return ;
    		}
    		int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    		if(ql <= mid) update(lc, l, mid, ql, qr, v);
    		if(qr > mid) update(rc, mid + 1, r, ql, qr, v);
    		maxv[o] = max(maxv[lc], maxv[rc]);
    		return ;
    	}
    	
    	int query(int o, int l, int r, int ql, int qr) {
    		if(!ql || !qr) return 0;
    		pushdown(o, l, r);
    		if(ql <= l && r <= qr) return maxv[o];
    		int mid = l + r >> 1, lc = o << 1, rc = lc | 1, ans = 0;
    		if(ql <= mid) ans = max(ans, query(lc, l, mid, ql, qr));
    		if(qr > mid) ans = max(ans, query(rc, mid + 1, r, ql, qr));
    		return ans;
    	}
    } seg;
    
    struct LCT {
    	int fa[maxn], ch[maxn][2], rt[maxn];
    	
    	void init() {
    		for(int i = 1; i <= n; i++) rt[i] = i, fa[i] = TREE::fa[i][0];
    		rt[0] = 0;
    //		for(int i = 1; i <= n; i++) printf("%d%c", fa[i], i < n ? ' ' : '
    ');
    		return ;
    	}
    	
    	bool isrt(int u) { return !fa[u] || (ch[fa[u]][0] != u && ch[fa[u]][1] != u); }
    	void maintain(int o) {
    		if(!o) return ;
    		if(ch[o][0]) rt[o] = rt[ch[o][0]];
    		else rt[o] = o;
    		return ;
    	}
    	void rotate(int u) {
    		int y = fa[u], z = fa[y], l = 0, r = 1;
    		if(!isrt(y)) ch[z][ch[z][1]==y] = u;
    		if(ch[y][1] == u) swap(l, r);
    		fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
    		ch[y][l] = ch[u][r]; ch[u][r] = y;
    		maintain(y); maintain(u);
    		return ;
    	}
    	void splay(int u) {
    		while(!isrt(u)) {
    			int y = fa[u], z = fa[y];
    			if(!isrt(y)) {
    				if(ch[y][0] == u ^ ch[z][0] == y) rotate(u);
    				else rotate(y);
    			}
    			rotate(u);
    		}
    		return ;
    	}
    	void access(int u) {
    		splay(u); seg.update(1, 1, n, dl[rt[ch[u][1]]], dr[rt[ch[u][1]]], 1); /*printf("+1s: %d
    ", rt[ch[u][1]]);*/ ch[u][1] = 0; maintain(u);
    		while(fa[u]) {
    			splay(fa[u]);
    			seg.update(1, 1, n, dl[rt[ch[fa[u]][1]]], dr[rt[ch[fa[u]][1]]], 1); // printf("+1s: %d
    ", rt[ch[fa[u]][1]]);
    			seg.update(1, 1, n, dl[rt[u]], dr[rt[u]], -1); // printf("-1s: %d
    ", rt[u]);
    			ch[fa[u]][1] = u;
    			maintain(fa[u]);
    			splay(u);
    		}
    		return ;
    	}
    } lct;
    
    int main() {
    	n = read(); int q = read();
    	for(int i = 1; i < n; i++) {
    		int a = read(), b = read();
    		AddEdge(a, b);
    	}
    	dep[1] = 0; build(1);
    	
    	seg.build(1, 1, n);
    	lct.init();
    	while(q--) {
    		int tp = read(), u = read(), v;
    		if(tp == 1) lct.access(u);
    		if(tp == 2) {
    			v = read(); int c = lca(u, v);
    //			printf("lca(%d, %d) = %d
    ", u, v, c);
    			printf("%d
    ", seg.query(1, 1, n, dl[u], dl[u]) + seg.query(1, 1, n, dl[v], dl[v]) - (seg.query(1, 1, n, dl[c], dl[c]) << 1) + 1);
    		}
    		if(tp == 3) printf("%d
    ", seg.query(1, 1, n, dl[u], dr[u]) + 1);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    sparql学习sparql示例、dbpedia在线验证
    中国绿卡
    逾期率的水有多深,你知道吗?
    ICO和区块链区别
    What are the benefits to using anonymous functions instead of named functions for callbacks and parameters in JavaScript event code?
    Link static data in sql source control
    sql data compare
    viewbag
    多态的实际使用
    win10 sedlauncher.exe占用cpu处理
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6735253.html
Copyright © 2011-2022 走看看