• CodeForces383C Propagating tree 思维 线段树 DFS序


    CodeForces383C Propagating tree 思维 线段树 DFS序

    题意

    给定一颗1为根的树,由(1-n)编号,每个点具有点权,两种操作:

    1. 1 u val 表示给(u)号点增加权值val,同时还会影响子树,它的所有子节点-val,所有子节点的子节点-(-val)....

    2. 2 u 表示查询u的点权

    [1 leq n,m leq 2 imes 10^5\ 1 leq a_i,val leq 1000\ ]

    分析

    我们发现每次只对单点或者一个子树操作,因此不必树链剖分,用DFS序即可维护。

    如果只是单纯+val的话就是线段树模板了,但是此题会在下一层减,怎么办呢?既然不方便在加上做文章,不妨考虑在询问时处理。

    规定:在奇数层操作时,全体加上val,否则减去val。在奇数层查询时,查维护的正值,否则取负号

    这正是利用了相邻层总是一正一负的性质,让询问变得简单。

    https://img2020.cnblogs.com/blog/1922757/202103/1922757-20210305201722236-1789756646.png

    当然,实现用树状数组更好

    代码

    #include<bits/stdc++.h>
    #define eps 1e-8
    #define equals(a,b) (fabs(a - b) < eps)
    using namespace std;
    
    typedef long long ll;
    
    const ll MOD = 1e9 + 7;
    
    ll rd(){
    	ll x = 0;
    	int f = 1;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') {
    		if(ch == -1) f = -1;
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9') {
    		x = x * 10 + ch - '0';
    		ch = getchar();
    	} 
    	return  x * f;
    }
    
    
    struct SegmentTree{
    	int n;
    	vector<int> sum,tag;
    	SegmentTree(){}
    	SegmentTree(int n):n(n),sum(((n + 1) << 2)),tag(((n + 1) << 2)) {}
    	int push_up(int i){
    		sum[i] = sum[i << 1] + sum[i << 1|1];
    	}
    	void update(int i,int l,int r,int v){
    		sum[i] += (r - l + 1) * v;
    		tag[i] += v;
    	}
    	void push(int i,int l,int r){
    		int mid = l + r >> 1;
    		if(tag[i]) {
    			update(i << 1,l,mid,tag[i]);
    			update(i << 1|1,mid + 1,r,tag[i]);
    			tag[i] = 0;
    		}
    	}
    	void update(int i,int l,int r,int L,int R,int v){
    		if(l > R || r < L) return;
    		if(l >= L && r <= R) return update(i,l,r,v);
    		int mid = l + r >> 1;
    		push(i,l,r);
    		update(i << 1,l,mid,L,R,v);
    		update(i << 1|1,mid + 1,r,L,R,v);
    		push_up(i);
    	} 
    	int query(int i,int l,int r,int L,int R){
    		if(l > R || r < L) return 0;
    		if(l >= L && r <= R) return sum[i];
    		int mid = l + r >> 1;
    		push(i,l,r);
    		return query(i << 1,l,mid,L,R) + query(i << 1|1,mid + 1,r,L,R); 
    	}
    };
    
    vector<int> e[200005];
    int l[200005];
    int r[200005];
    int dep[200005];
    int tt;
    
    void dfs(int u,int fa){
    	l[u] = ++tt;
    	for(auto it:e[u]) {
    		if(it == fa) continue;
    		dep[it] = dep[u] + 1;
    		dfs(it,u);		
    	}
    	r[u] = tt;
    }
    
    
    
    int main(){
    	int n = rd();
    	SegmentTree seg(n);
    	vector<int> val(n + 1);
    	int m = rd();
    	for(int i = 1;i <= n;i++){
    		val[i] = rd();
    	}
    	for(int i = 1;i < n;i++){
    		int u = rd();
    		int v = rd();
    		e[u].push_back(v);
    		e[v].push_back(u);
    	}
    	dfs(1,0);
    	while(m--){
    		int op = rd();
    		if(op == 1)  {
    			int x = rd();
    			int y = rd();
    			if(dep[x] & 1) {
    				seg.update(1,1,n,l[x],r[x],y);
    			}
    			else seg.update(1,1,n,l[x],r[x],-y);
    		}
    		else{
    			int x = rd();
    			if(dep[x] & 1) {
    				printf("%d
    ",val[x] + seg.query(1,1,n,l[x],l[x]));
    			}
    			else printf("%d
    ",val[x] - seg.query(1,1,n,l[x],l[x]));
    		}
    	}
    }
    

  • 相关阅读:
    C#操作LX3600非接触式IC卡读写器
    jquery easyui datagrid 动态改变url地址中的参数值
    给javascript添加事件
    解决远程连接mysql很慢的问题(mysql_connect 打开连接慢)
    not in和not exists的区别
    sql中case when then的用法
    SQL查询重复数据
    SQL 批量添加的语法
    SQL函数和存储过程的区别
    SQL type in 语法
  • 原文地址:https://www.cnblogs.com/hznumqf/p/14488238.html
Copyright © 2020-2023  润新知