• 洛谷P3178[HAOI]2015 树上操作


    题目

    树剖裸题,这个题更可以深刻的理解树剖中把树上的节点转换为区间的思想。

    要注意在区间上连续的节点,一定是在一棵子树中。

    #include <bits/stdc++.h>
    #define int long long 
    #define ls left, mid, root << 1
    #define rs mid + 1, right, root << 1 | 1
    #define N 600100	
    using namespace std;
    int n, m, rot, mod, tot, cnt;	
    int data[N], id[N], dep[N], size[N], lin[N], ans[N * 8], lazy[N * 8], dp[N], fa[N], top[N], son[N];
    struct edg {
    	int to, nex;
    } e[N];
    inline void add(int f, int t)
    {
    	e[++cnt].to = t;
    	e[cnt].nex = lin[f];
    	lin[f] = cnt;
    }			
    inline void pushup(int root)
    {
     	ans[root] = (ans[root << 1] + ans[root << 1 | 1]);
    }	 
    inline void pushdown(int root, int left, int right)
    { 
      	int mid = (left + right) >> 1;
       	if (lazy[root])
       	{
    		ans[root << 1] += (mid - left + 1) * lazy[root];
    		ans[root << 1];
    		ans[root << 1 | 1] += (right - mid) * lazy[root];
    		ans[root << 1 | 1];
    		lazy[root << 1] += lazy[root]; 
    		lazy[root << 1 | 1] += lazy[root];
    		lazy[root] = 0; 
    	}
    }
    void build(int left, int right, int root)
    {
    	if (left == right)
    	{	
    		ans[root] = dp[left], ans[root];
    		return;		
    	}				
    	int mid = (left + right) >> 1;
    	build(ls), build(rs);
    	pushup(root);	
    }					
    inline void update(int left, int right, int root, int add, int ql, int qr)
    {	
    	if (left >= ql && right <= qr)
    	{
    		ans[root] += (right - left + 1) * add;
    		lazy[root] += add;	   
    		ans[root];
    		return;				   
    	}						   
    	int mid = (left + right) >> 1;
    	pushdown(root, left, right);//线段树的pushdown操作是为了弥补之前没向下传递标记的坑。 
    	if (ql <= mid)			   	
    		update(ls, add, ql, qr);
    	if (qr > mid)			   	
    		update(rs, add, ql, qr);
    	pushup(root);			   	
    }	
    inline int query(int left, int right, int root, int ql, int qr)
    {
    	int res = 0;
    	if (left >= ql && right <= qr)
    		return ans[root];
    	int mid = (left + right) >> 1;
    	pushdown(root, left, right);
    	if (ql <= mid)
    		res = ( res + query(ls, ql, qr) );
    	if (qr > mid)
    		res = res + query(rs, ql, qr) ;
    	return res;
    }
    void dfs1(int now, int f, int de)
    {	
    	fa[now] = f, dep[now] = de, size[now] = 1;
    	int maxsize = -1;
    	for (int i = lin[now]; i; i = e[i].nex)
    	{
    		if (e[i].to == f) continue;
    		dfs1(e[i].to, now, de + 1);
    		size[now] += size[e[i].to];
    		if (size[e[i].to] > maxsize)
    		{
    			maxsize = size[e[i].to];
    			son[now] = e[i].to;
    		}
    	}
    }	
    void ulca(int x, int y, int z)
    {
    	while (top[x] != top[y])
    	{
    		if (dep[top[x]] < dep[top[y]])
    			swap(x, y);
    		update(1, n, 1, z, id[top[x]], id[x]);
    		x = fa[top[x]];
    	}
    	if (dep[x] > dep[y])
    		swap(x, y);
    	update(1, n, 1, z, id[x], id[y]); 
    }
    int qlca(int x, int y)
    {
    	int res = 0;
    	while (top[x] != top[y])
    	{
    		if (dep[top[x]] < dep[top[y]])
    			swap(x, y);
    		res = ( res + query(1, n, 1, id[top[x]], id[x]) );
    		x = fa[top[x]];
    	}
    	if (dep[x] > dep[y])
    		swap(x, y);
    	res = ( res + query(1, n, 1, id[x], id[y]) );
    	return res;
    }
    void upd(int x, int y) 
    {
    	update(1, n, 1, y, id[x], id[x] + size[x] - 1);
    }
    int que(int x) 
    {
    	return query(1, n, 1, id[x], id[x] + size[x] - 1);
    }
    void dfs2(int now, int t)
    {
    	top[now] = t;
    	dp[++tot] = data[now];
    	id[now] = tot;
    	if (!son[now])
    		return;
    	dfs2(son[now], t);
    	for (int i = lin[now]; i; i = e[i].nex)
    	{
    		int to = e[i].to;
    		if (to != fa[now] && to != son[now])
    			dfs2(to, to);
    	}
    }
    signed main()
    {
    	scanf("%lld%lld", &n, &m);
    	rot = 1;
    	for (int i = 1; i <= n; i++)
    			scanf("%lld", &data[i]); 
    	for (int i = 1; i < n; i++)
    	{
    		int a, b;
    		scanf("%lld%lld", &a, &b);
    		add(a, b);
    		add(b, a);
    	}
    	dfs1(rot, 0, 1);
    	dfs2(rot, rot);
    	build(1, n, 1); 
    	for (int i = 1; i <= m; i++)
    	{	
    		int flag;
    		scanf("%lld", &flag);
    		if (flag == 1)
    		{
    			int x, a;
    			scanf("%lld%lld", &x, &a);
    			update(1, n, 1, a, id[x], id[x]);
    		}
    		if (flag == 2)
    		{
    			int x, a;
    			scanf("%lld%lld", &x, &a);
    			update(1, n, 1, a, id[x],  id[x] + size[x] - 1);
    		}
    		if (flag == 3)
    		{
    			int a;
    			scanf("%lld", &a);
    			printf("%lld
    ", qlca(1, a));//不能写成id[1],id[a]因为id子树之间是连续的,所以a到1之间并不是连续边号。 
    		}
    	}	
    	return 0;
    }
    /*
    5 5 2 24
    7 3 7 8 0 
    1 2
    1 5
    3 1
    4 1
    3 4 2
    3 2 2
    4 5
    1 5 1 3
    2 1 3
    */
    
  • 相关阅读:
    Java面向对象知识点总结
    JAVA编程必学必会单词集(1)
    Linux 帮助命令
    学习笔记
    day4
    复习
    day5
    day04
    day3
    day02
  • 原文地址:https://www.cnblogs.com/liuwenyao/p/11229609.html
Copyright © 2020-2023  润新知