树链剖分+线段树--CF1076E Vasya and a Tree

传送门
题意就是给你一颗 n n n个点的树,一开始权值都是 0 0 0,然后 m m m个操作,每个操作对一个点 x x x的子树中到它距离不超过 d d d的点权都加上 v a l val val,问最后所有点的点权是多少

对于子树的修改可以用树剖+线段树做到,但是对于半个子树的修改很难做到,那就可以将修改操作排一下序,按照 d e p [ x ] + d dep[x]+d dep[x]+d从大到小排,这样的话当修改完了一层,后面的修改都不会修改到这一层,就可以先把这一层的答案记下来,每次只需要修改子树就好了

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define N 300005
#define LL long long
#define ls cur<<1
#define rs cur<<1|1
#define len(x) (node[x].r-node[x].l+1)
using namespace std;

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f;
}

int n,cnt,head[N],to[N<<1],nxt[N<<1],m;
LL ans[N];
int dep[N],dfn[N],rk[N],son[N],top[N],fa[N],siz[N],num;
vector<int> vec[N];

inline void add(int x,int y){to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;}

struct QWQ{
	int x,d,val;
	bool operator <(const QWQ &y) const{
		return dep[x]+d>dep[y.x]+y.d;
	}
}a[N];

void dfs1(int u,int fat){
	siz[u]=1; int maxson=-1;
	for(int i=head[u];i;i=nxt[i]){
		int v=to[i]; if(v==fat) continue;
		dep[v]=dep[u]+1; fa[v]=u; vec[dep[v]].push_back(v);
		dfs1(v,u); siz[u]+=siz[v];
		if(maxson<siz[v]) maxson=siz[v],son[u]=v;
	} return;
}

void dfs2(int u,int t){
	dfn[u]=++num; rk[num]=u; top[u]=t;
	if(!son[u]) return ;
	dfs2(son[u],t);
	for(int i=head[u];i;i=nxt[i]){
		int v=to[i];
		if(!dfn[v]) dfs2(v,v);
	}
}

struct Node{
	LL sum,lazy; int l,r;
}node[N<<2];
inline void pushup(int cur){node[cur].sum=node[ls].sum+node[rs].sum;}
inline void pushdown(int cur){
	if(!node[cur].lazy) return;
	LL t=node[cur].lazy; node[cur].lazy=0;
	node[ls].sum+=1LL*len(ls)*t; node[ls].lazy+=t;
	node[rs].sum+=1LL*len(rs)*t; node[rs].lazy+=t;
}

void build(int cur,int L,int R){
	if(L==R){
		node[cur].l=node[cur].r=L;
		return;
	}
	int mid=(L+R)>>1;
	build(ls,L,mid); build(rs,mid+1,R);
	node[cur].l=node[ls].l; node[cur].r=node[rs].r;
}

void update(int cur,int L,int R,int c){
	if(L<=node[cur].l && node[cur].r<=R){
		node[cur].sum+=1LL*len(cur)*c; node[cur].lazy+=c;
		return;
	}
	pushdown(cur);
	int mid=(node[cur].l+node[cur].r)>>1;
	if(L<=mid) update(ls,L,R,c);
	if(mid<R) update(rs,L,R,c);
	pushup(cur);
}

LL query(int cur,int L,int R){
	if(L<=node[cur].l && node[cur].r<=R) return node[cur].sum;
	pushdown(cur);
	int mid=(node[cur].l+node[cur].r)>>1; LL res=0;
	if(L<=mid) res+=query(ls,L,R);
	if(mid<R) res+=query(rs,L,R);
	return res;
}

int main(){
	n=rd();
	for(int i=1;i<n;i++){
		int x=rd(),y=rd();
		add(x,y); add(y,x);
	}
	m=rd();
	for(int i=1;i<=m;i++){
		a[i].x=rd(),a[i].d=rd(),a[i].val=rd();
	}
	dep[1]=1; vec[1].push_back(1); dfs1(1,0); dfs2(1,1); build(1,1,n);
	sort(a+1,a+m+1); int mx=0,pre;
	for(int i=1;i<=n;i++) mx=max(mx,dep[i]); pre=mx;
	for(int i=1;i<=m;i++){
		int now=dep[a[i].x]+a[i].d;
		while(pre>now) {
			for(int j=0;j<vec[pre].size();j++){
				int u=vec[pre][j]; ans[u]=query(1,dfn[u],dfn[u]);
			} pre--;
		}
		update(1,dfn[a[i].x],dfn[a[i].x]+siz[a[i].x]-1,a[i].val);
	}
	while(pre>=1){
		for(int j=0;j<vec[pre].size();j++){
			int u=vec[pre][j]; ans[u]=query(1,dfn[u],dfn[u]);
		} pre--;
	}
	for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值