zoukankan      html  css  js  c++  java
  • CF916E

    Codeforces 916E 简要题解Description

    Description

    有一棵n个点的树,每个节点上有一个权值wi,最开始根为1号点.现在有3种类型的操作:
    1 root, 表示将根设为root.
    2 u v x, 设u, v的最近公共祖先为p, 将p的子树中的所有点的权值加上x.
    3 u, 查询u的子树中的所有点的权值和.
    对于每个3操作,输出答案.

    n <= 500000

    Solution

    ​ 考虑不能直接换根. 换了根就完了

    ​ 那么我们考虑另一种办法,就是如何保持原来树的形态的情况下模拟出各个根的情况。

    ​ 那么考虑分类讨论,如果根不在一个节点的子树中,那么直接操作就可以。否则就对整棵树进行操作, 然后再减去多余的一部分就可以。

    ​ 新树中的LCA(u, v) 就是LCA(u, v), LCA(u, root), LCA(v, root)深度最大的点, 因为它最接近新根。

    ​ 然后直接操作就可以了

    ​ 考虑一些细节: 如果根是当前操作点就直接对整棵树进行操作即可。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
    #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
    #define clar(a, b) memset((a), (b), sizeof(a))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    #define Debug(s) debug("The massage in line %d, Function %s: %s
    ", __LINE__, __FUNCTION__, s)
    typedef long long LL;
    typedef long double LD;
    const int BUF_SIZE = (int)1e6 + 10;
    struct fastIO {
        char buf[BUF_SIZE], buf1[BUF_SIZE];
        int cur, cur1;
        FILE *in, *out;
        fastIO() {
            cur = BUF_SIZE, in = stdin, out = stdout;
    		cur1 = 0;
        }
        inline char getchar() {
            if(cur == BUF_SIZE) fread(buf, BUF_SIZE, 1, in), cur = 0;
            return *(buf + (cur++));
        }
        inline void putchar(char ch) {
            *(buf1 + (cur1++)) = ch;
            if (cur1 == BUF_SIZE) fwrite(buf1, BUF_SIZE, 1, out), cur1 = 0;
        }
        inline int flush() {
            if (cur1 > 0) fwrite(buf1, cur1, 1, out);
            return cur1 = 0;
        }
    }IO;
    #define getchar IO.getchar
    #define putchar IO.putchar
    LL read() {
    	char ch = getchar();
    	LL x = 0, flag = 1;
    	for(;!isdigit(ch); ch = getchar()) if(ch == '-') flag *= -1;
    	for(;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    	return x * flag;
    }
    void write(LL x) {
    	if(x < 0) putchar('-'), x = -x;
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + 48);
    }
    void putString(char s[], char EndChar = '
    ') {
    	rep(i, 0, strlen(s) - 1) putchar(*(s + i));
    	if(~EndChar) putchar(EndChar);
    }
    
    #define Maxn 500009
    struct edge {
    	int nxt, to;
    }g[Maxn << 1];
    int head[Maxn], e;
    int a[Maxn];
    int n, q,  size[Maxn], dep[Maxn], son[Maxn], dfn[Maxn], efn[Maxn], _index, fa[Maxn], top[Maxn];
    namespace INIT {
    	inline void add(int u, int v) {
    		g[++e] = {head[u], v}, head[u] = e;
    		g[++e] = {head[v], u}, head[v] = e;
    	}
    	void dfs_init(int u, int f) {
    		dep[u] = dep[f] + 1, size[u] = 1;
    		fa[u] = f;
    		for(int i = head[u]; ~i; i = g[i].nxt) {
    			int v = g[i].to;
    			if(v != f) {
    				dfs_init(v, u);
    				size[u] += size[v];
    				if(son[u] == -1 || size[son[u]] < size[v]) son[u] = v;
    			}
    		}
    	}
    	void dfs_son(int u, int _top) {
    		efn[++_index] = u, dfn[u] = _index;
    		top[u] = _top;
    		if(~son[u]) dfs_son(son[u], _top); else return;
    		for(int i = head[u]; ~i; i = g[i].nxt) {
    			int v = g[i].to;
    			if(v != fa[u] && v != son[u]) dfs_son(v, v);
    		}
    	}
    	void Main() {
    		clar(head, -1), clar(son, -1);
    		n = read(), q = read();
    		rep(i, 1, n) a[i] = read();
    		rep(i, 1, n - 1) add(read(), read());
    		dfs_init(1, 0);
    		dfs_son(1, 1);
    	}
    }
    namespace SGMT_tree {
    	LL tree[Maxn * 8], add[Maxn * 8];
    #define lc(x) ((x) << 1)
    #define rc(x) ((x) << 1 | 1)
    #define ls rt << 1, l, mid
    #define rs rt << 1 | 1, mid + 1, r
    	inline void pushup(int rt) { tree[rt] = tree[lc(rt)] + tree[rc(rt)]; }
    	inline void pushdown(int rt, int l, int r) {
    		int mid = (l + r) >> 1;
    		if(add[rt]) {
    			tree[lc(rt)] += (mid - l + 1ll) * add[rt];
    			add[lc(rt)] += add[rt];
    			tree[rc(rt)] += (r - mid * 1ll) * add[rt];
    			add[rc(rt)] += add[rt];
    			add[rt] = 0;
    		}
    	}
    	void build(int rt, int l, int r) {
    		add[rt] = 0;
    		if(l == r) { tree[rt] = a[efn[l]]; return ; }
    		int mid = (l + r) >> 1;
    		build(ls), build(rs);
    		pushup(rt);
    	}
    	void modify(int rt, int l, int r, int x, int y, int val) {
    		if(x <= l && r <= y) {
    			tree[rt] += val * 1ll * (r - l + 1), add[rt] += (LL)val;
    			return;
    		}
    		int mid = (l + r) >> 1;
    		pushdown(rt, l, r);
    		if(y <= mid) modify(ls, x, y, val);
    		else if(x >= mid + 1) modify(rs, x, y, val);
    		else modify(ls, x, y, val), modify(rs, x, y, val);
    		pushup(rt);
    	}
    	LL query(int rt, int l, int r, int x, int y) {
    		if(x <= l && r <= y) return tree[rt];
    		int mid = (l + r) >> 1; LL res = 0;
    		pushdown(rt, l, r);
    		if(x <= mid) res = res + query(ls, x, y);
    		if(y >= mid + 1) res = res + query(rs, x, y);
    		return res;
    	}
    }
    namespace SOLVE {
    	int root;
    	int LCA(int u, int v) {
    		while(top[u] != top[v]) {
    			if(dep[top[u]] < dep[top[v]]) swap(u, v);
    			u = fa[top[u]];
    		}
    		return dep[u] < dep[v] ? u : v;
    	}
    	int lca_New(int u, int v) {
    		int lca1 = LCA(u, v), lca2 = LCA(u, root), lca3 = LCA(v, root);
    		int Ans = INT_MIN, Ans1 = -1;
    		if(dep[lca1] > Ans) { Ans = dep[lca1]; Ans1 = lca1; }
    		if(dep[lca2] > Ans) { Ans = dep[lca2]; Ans1 = lca2; }
    		if(dep[lca3] > Ans) { Ans = dep[lca3]; Ans1 = lca3; }
    		assert(Ans1 != -1);
    		return Ans1;
    	}
    	int ninrt(int u) {
    		if(root == u) return 0;
    		if(dfn[root] < dfn[u] || dfn[root] > dfn[u] + size[u] - 1) return 0;
    		return 1;
    	}
    	int Find(int u, int anc) {
    		while(top[u] != top[anc]) {
    			if(fa[top[u]] == anc) return top[u];
    			u = fa[top[u]];
    		}
    		return son[anc];
    	}
    	void Main() {
    		root = 1;
    		SGMT_tree :: build(1, 1, n);
    		rep(i, 1, q) {
    			int opt = read();
    			if(opt == 1) root = read();
    			if(opt == 2) {
    				int u = read(), v = read(), val = read(), lca = lca_New(u, v);
    				if(lca == root) SGMT_tree :: modify(1, 1, n, 1, n, val);
    				else if(ninrt(lca)) {
    					int RootOther = Find(root, lca);
    					SGMT_tree :: modify(1, 1, n, 1, n, val);
    					SGMT_tree :: modify(1, 1, n, dfn[RootOther], dfn[RootOther] + size[RootOther] - 1, -val);
    				}else SGMT_tree :: modify(1, 1, n, dfn[lca], dfn[lca] + size[lca] - 1, val);
    			}
    			if(opt == 3) {
    				int u = read(); LL res = 0;
    				if(u == root) res = SGMT_tree :: query(1, 1, n, 1, n);
    				else if(ninrt(u)) {
    					int RootOther = Find(root, u);
    					res += SGMT_tree :: query(1, 1, n, 1, n);
    					res -= SGMT_tree :: query(1, 1, n, dfn[RootOther], dfn[RootOther] + size[RootOther] - 1);
    				}else res += SGMT_tree :: query(1, 1, n, dfn[u], dfn[u] + size[u] - 1);
    				write(res), putchar('
    ');
    			}
    		}
    	}
    }
    int main() {
    #ifdef Qrsikno
    	freopen("CF916E.in", "r", stdin);
    	freopen("CF916E.out", "w", stdout);
    #endif
    	INIT :: Main();
    	SOLVE :: Main();
    #ifdef Qrsikno
    	debug("
    Running time: %.3lf(s)
    ", clock() * 1.0 / CLOCKS_PER_SEC);
    #endif
    	return IO.flush();
    }
    
    
  • 相关阅读:
    查看eclipse web项目中jsp编译后的servlet源文件【转】【JSP】
    综合实战--文件上传系统【JDBC&IO&Socket】
    002、使用webpack的各种loader处理文件
    001、node & webpack工程手动搭建
    000、GO之特别语法糖
    000、GO之深刻理解拷贝
    000、常见算法解析
    003、GO之并发
    002、GO之反射
    001、GO之指针转换
  • 原文地址:https://www.cnblogs.com/qrsikno/p/9780666.html
Copyright © 2011-2022 走看看