zoukankan      html  css  js  c++  java
  • P3833 [SHOI2012]魔法树

    $ color{#0066ff}{ 题目描述 }$

    Harry Potter 新学了一种魔法:可以让改变树上的果子个数。满心欢喜的他找到了一个巨大的果树,来试验他的新法术。

    这棵果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u],保证有fa[u] < u。初始时,这棵果树上的果子都被 Dumbledore 用魔法清除掉了,所以这个果树的每个节点上都没有果子(即0个果子)。

    不幸的是,Harry 的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry 的魔法可以这样描述:

    Add u v d

    表示将点u和v之间的路径上的所有节点的果子个数都加上d。

    接下来,为了方便检验 Harry 的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:

    Query u

    表示当前果树中,以点u为根的子树中,总共有多少个果子?

    (color{#0066ff}{输入格式})

    第一行一个正整数N (1 ≤ N ≤ 100000),表示果树的节点总数,节点以0,1,…,N − 1标号,0一定代表根节点。

    接下来N − 1行,每行两个整数a,b (0 ≤ a < b < N),表示a是b的父亲。

    接下来是一个正整数Q(1 ≤ ? ≤ 100000),表示共有Q次操作。

    后面跟着Q行,每行是以下两种中的一种:

    A u v d,表示将u到v的路径上的所有节点的果子数加上d;0 ≤ u,v <N,0 < d < 100000

    Q u,表示询问以u为根的子树中的总果子数,注意是包括u本身的。

    (color{#0066ff}{输出格式})

    对于所有的Query操作,依次输出询问的答案,每行一个。答案可能会超过2^32 ,但不会超过10^15 。

    (color{#0066ff}{输入样例})

    4
    0 1
    1 2
    2 3
    4
    A 1 3 1
    Q 0
    Q 1
    Q 2
    

    (color{#0066ff}{输出样例})

    3
    3
    2
    

    (color{#0066ff}{数据范围与提示})

    none

    (color{#0066ff}{题解})

    显然树剖裸题

    一个是路径加,跳重链(O(nlog^2n))

    询问直接线段树区间查询即可

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int maxn = 1e5 + 10;
    struct Tree  {
    protected:
    	struct node {
    		node *ch[2];
    		int l, r;
    		LL val, tag;
    		node(int l = 0, int r = 0, LL val = 0, LL tag = 0): l(l), r(r), val(val), tag(tag) {
    			ch[0] = ch[1] = NULL;
    		}
    		void add(LL v) { tag += v, val += (r - l + 1) * v; }
    		void upd() { val = ch[0]->val + ch[1]->val; }
    		int mid() { return (l + r) >> 1; }
    		void dwn() {
    			if(!tag) return;
    			ch[0]->add(tag), ch[1]->add(tag);
    			tag = 0;
    		}
    	}*root;
    	void build(node *&o, int l, int r) {
    		o = new node(l, r);
    		if(l == r) return;
    		int mid = (l + r) >> 1;
    		build(o->ch[0], l, mid);
    		build(o->ch[1], mid + 1, r);
    	}
    	void lazy(node *o, int l, int r, LL val) {
    		if(l <= o->l && o->r <= r) return o->add(val);
    		o->dwn();
    		if(l <= o->mid()) lazy(o->ch[0], l, r, val);
    		if(r > o->mid()) lazy(o->ch[1], l, r, val);
    		o->upd();
    	}
    	LL query(node *o, int l, int r) {
    		if(l <= o->l && o->r <= r) return o->val;
    		o->dwn();
    		LL ans = 0;
    		if(l <= o->mid()) ans += query(o->ch[0], l, r);
    		if(r > o->mid()) ans += query(o->ch[1], l, r);
    		return ans;
    	}
    public:
    	Tree() { root = NULL; }
    	void build(int l, int r) { build(root, l, r); }
    	void lazy(int l, int r, LL val) { lazy(root, l, r, val); }
    	LL query(int l, int r) { return query(root, l, r); }
    }s;
    int top[maxn], dfn[maxn], siz[maxn], fa[maxn], n, cnt;
    int dep[maxn], son[maxn], nfd[maxn];
    struct node {
    	int to;
    	node *nxt;
    	node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
    };
    node *head[maxn];
    void add(int from, int to) {
    	head[from] = new node(to, head[from]);
    }
    void dfs1(int x, int f) {
    	dep[x] = dep[fa[x] = f] + (siz[x] = 1);
    	for(node *i = head[x]; i; i = i->nxt) {
    		if(i->to == f) continue;
    		dfs1(i->to, x);
    		siz[x] += siz[i->to];
    		if(!son[x] || siz[i->to] > siz[son[x]]) son[x] = i->to;
    	}
    }
    void dfs2(int x, int t) {
    	top[nfd[dfn[x] = ++cnt] = x] = t;
    	if(son[x]) dfs2(son[x], t);
    	for(node *i = head[x]; i; i = i->nxt) 
    		if(!dfn[i->to]) dfs2(i->to, i->to);
    }
    void addpath(int x, int y, LL val) {
    	int fx = top[x], fy = top[y];
    	while(fx != fy) {
    		if(dep[fx] >= dep[fy]) {
    			s.lazy(dfn[fx], dfn[x], val);
    			x = fa[fx];
    		}
    		else {
    			s.lazy(dfn[fy], dfn[y], val);
    			y = fa[fy];
    		}
    		fx = top[x];
    		fy = top[y];
    	}
    	if(dep[x] < dep[y]) std::swap(x, y);
    	s.lazy(dfn[y], dfn[x], val);
    }
    char getch() { 
    	char ch;
    	while(!isalpha(ch = getchar()));
    	return ch;
    }
    int main() {
    	int n = in();
    	int x, y;
    	LL z;
    	for(int i = 1; i < n; i++) x = in(), y = in(), add(x, y);
    	dfs1(0, n + 1), dfs2(0, 0), s.build(1, n);
    	for(int T = in(); T --> 0;) {
    		if(getch() == 'A') x = in(), y = in(), z = in(), addpath(x, y, z);
    		else x = in(), printf("%lld
    ", s.query(dfn[x], dfn[x] + siz[x] - 1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    【转】VS2010中 C++创建DLL图解
    [转]error: 'retainCount' is unavailable: not available in automatic reference counting mode
    [转]关于NSAutoreleasePool' is unavailable: not available in automatic reference counting mode的解决方法
    【转】 Tomcat v7.0 Server at localhost was unable to start within 45
    【转】Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If
    【转】SVN管理多个项目版本库
    【转】eclipse安装SVN插件的两种方法
    【转】MYSQL启用日志,和查看日志
    【转】Repository has not been enabled to accept revision propchanges
    【转】SVN库的迁移
  • 原文地址:https://www.cnblogs.com/olinr/p/10458517.html
Copyright © 2011-2022 走看看