zoukankan      html  css  js  c++  java
  • Codeforces 1076E Vasya and a Tree(树状数组)或dfs

    题意:给你一颗以1为根节点的树,初始所有节点的权值为0,然后有m个操作,每个操作将点x的所有距离不超过d的节点权值+1,问经过m次操作后每个节点权值是多少?

    思路:如果是一个序列,就可以直接用树状数组做,但这是一颗树,所以我们可以想办法把它转化成序列。我们可以先求出每个节点的dfs序,以及深度和子树的大小,顺便记录每个深度都有哪些节点,子树的大小用来确认以该节点为根的子树在dfs序中的范围,此时便可用树状数组维护了。之后,我们把每个操作按能影响到的深度从大到小排序,即优先处理影响深度大的操作。设当前计算的深度为now,假设所有操的作影响的深度大于now的操作已经计算。如果当前操作影响的深度小于now,说明所有能影响到now深度的操作已经全部操作完了,此时把所有深度为now的节点权值计算出来。每读取一个操作的信息,就把操作产生的影响用树状数组维护,因为影响now深度的节点权值已经计算完毕了,所以我把以该操作的操作节点为根的子树全部加上操作的值 对之前已经计算的答案没有影响。操作全部完成后,深度从深到浅计算答案即可。

    代码:

    #include<bits/stdc++.h>
    #define LL long long
    #define lowbit(x) (x&(-(x)))
    using namespace std;
    const int maxn=300010;
    int deep[maxn],head[maxn],Next[maxn*2],ver[maxn*2],tot,cnt;
    int sum[maxn],sz[maxn],dfsn[maxn],mx,n;
    LL c[maxn],ans[maxn];
    struct op{
    	int x,d;
    	LL num;
    	bool operator <(const op& rhs)const{
    		return (deep[x]+d)>(deep[rhs.x]+rhs.d);
    	} 
    }OP[maxn];
    void adde(int x,int y){
    	ver[++tot]=y;
    	Next[tot]=head[x];
    	head[x]=tot;
    }
    vector<int>re[maxn];
    int get_deep(int x,int dep){
    	deep[x]=dep;
    	dfsn[x]=++cnt;
    	sz[x]=1;
    	mx=max(mx,dep);
    	re[dep].push_back(x);
    	for(int i=head[x];i;i=Next[i]){
    		int y=ver[i];
    		if(!deep[y]){
    			get_deep(y,dep+1);
    			sz[x]+=sz[y];
    		}
    	}
    }
    LL ask(int x){
    	LL ans=0;
    	for(;x;x-=lowbit(x))ans+=c[x];
    	return ans;
    }
    void add(int x,LL y){
    	for(;x<=n;x+=lowbit(x))c[x]+=y;
    }
    int main(){
    	int m;
    	scanf("%d",&n);
    	for(int i=1;i<n;i++){
    		int a,b;
    		scanf("%d%d",&a,&b);
    		adde(a,b);
    		adde(b,a);
    	}
    	get_deep(1,1);
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++){
    		int a,b;
    		LL c;
    		scanf("%d%d%lld",&a,&b,&c);
    		OP[i]=(op){a,b,c};
    	}
    	sort(OP+1,OP+1+m);
    	int now=mx;
    	for(int i=1;i<=m;i++){
    		int tmp=deep[OP[i].x]+OP[i].d;
    		while(now>tmp){
    			for(int j=0;j<re[now].size();j++){
    				int x=re[now][j];
    				ans[x]=ask(dfsn[x]);
    			}
    			now--;
    		}
    		add(dfsn[OP[i].x],OP[i].num);
    		add(dfsn[OP[i].x]+sz[OP[i].x],-OP[i].num);
    	}
    	while(now){
    		while(now){
    			for(int j=0;j<re[now].size();j++){
    				int x=re[now][j];
    				ans[x]=ask(dfsn[x]);
    			}
    			now--;
    		}
    	}
    	for(int i=1;i<=n;i++)
    		printf("%lld ",ans[i]);
    } 
    

      还有一种只用dfs的做法,dfs时,记录一下以该节点为起点的所有操作影响的深度范围(类似前缀和的方式),在从该节点回溯时再把影响减去,因为dfs时只会在子树中遍历,所以用这种方法就把影响限制在了子树的规定深度中。

    代码:

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    #define LL long long
    using namespace std;
    const int maxn=300010;
    int deep[maxn],head[maxn],Next[maxn*2],ver[maxn*2],tot,cnt;
    int now[maxn];
    LL ans[maxn];
    int n,m;
    vector< pair<int,LL> >re[maxn];
    void add(int x,int y){
    	ver[++tot]=y;
    	Next[tot]=head[x];
    	head[x]=tot;
    }
    void dfs(int x,LL val){
    	val+=now[deep[x]];
    	for(int i=0;i<re[x].size();i++){
    		int dep=deep[x]+re[x][i].fi;
    		dep=min(dep,n);
    		now[dep+1]-=re[x][i].se;
    		val+=re[x][i].se;
    	}
    	ans[x]=val;
    	for(int i=head[x];i;i=Next[i]){
    		int y=ver[i];
    		if(!deep[y]){
    			deep[y]=deep[x]+1;
    			dfs(y,val);
    		}
    	}
    	for(int i=0;i<re[x].size();i++){
    		int dep=deep[x]+re[x][i].fi;
    		dep=min(dep,n);
    		now[dep+1]+=re[x][i].se;
    	}
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<n;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add(x,y);
    		add(y,x);
    	}
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++){
    		int x,y;
    		LL z;
    		scanf("%d%d%lld",&x,&y,&z);
    		re[x].pb(mk(y,z));
    	}
    	deep[1]=1;
    	dfs(1,0);
    	for(int i=1;i<=n;i++)
    		printf("%lld ",ans[i]);
    } 
    

      

  • 相关阅读:
    随机产生16进制颜色值
    关于单元测试的思考--Asp.Net Core单元测试最佳实践
    使用xUnit为.net core程序进行单元测试
    SQLSERVER——查看阻塞信息(sp_who_lock优化无误版)
    SQLServer连接查询之Cross Apply和Outer Apply的区别及用法
    .netcore 写日志(使用NLog,log4net)
    概率与影响矩阵
    WebApi Helper帮助文档 swagger
    C# 使用HttpWebRequest Post提交数据,携带Cookie和相关参数示例
    解决哈希(HASH)冲突的主要方法
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/9955562.html
Copyright © 2011-2022 走看看