CF383C 树状数组+dfs序

4 篇文章 0 订阅

改变一下标dfs序的顺序就可以变成裸题了。
在这里插入图片描述
这是老的dfs序但是这样子不方便修改。
我们标dfs序的时候隔层标,变成这样在这里插入图片描述
隔层标的好处是对于题目而言的每一个修改操作,操作符相同的几个点的dfs序是连续的,这样我们就可以分两次改变两个连续区间,就是变成一道裸体了。举个例子比如我改变1的值,那么[2,3]区间是+val, [4,5]区间是-val,这就可以完成题目的要求。
关于如何这个连续区间是多少,从哪里开始,你在写个简单dp维护一下就可以了

int N,M;
ll c[max_];
il int lowbit(int x) { return x & (-x); }
il void change(int x, ll v) {
	while (x <= N) {
		c[x] += v;
		x += lowbit(x);
	}
}
il ll ask(int x) {
	int ans = 0;
	while (x){
		ans += c[x];
		x -= lowbit(x);
	}return ans;
}
int dfn[max_], tt;
vector<int> xian[max_];
void dfs(int now, int fa,int dep,int op) {
	if (dep % 2 == op % 2)dfn[now] = ++tt;
	for (auto to : xian[now]) {
		if (to == fa)continue;
		dfs(to, now, dep + 1, op);
	}
}
struct {
	int start, siz;
}f[max_][3];
void dfs2(int now, int fa) {
	f[now][1].start = f[now][0].start = inf;
	for (auto to : xian[now]) {
		if (to == fa)continue;
		dfs2(to, now);
		f[now][0].start = min(f[now][0].start, dfn[to]);
		f[now][0].siz += 1 + f[to][1].siz;

		f[now][1].start = min(f[now][1].start, f[to][0].start);
		f[now][1].siz += f[to][0].siz;
	}
}
int node[max_];
il void ini() {
	N = read(); M = read();
	re int A,B,i,temp;
	for (i = 1; i <= N; i++) {
		node[i] = read();
	}
	for (i = 1; i < N; i++) {
		A = read(); B = read();
		xian[A].push_back(B);
		xian[B].push_back(A);
	}
	dfs(1, 0, 0, 0); dfs(1, 0, 0, 1);
	for (i = 1; i <= N; i++) {
		change(dfn[i], node[i]);
		change(dfn[i] + 1, -node[i]);
	}
	dfs2(1, 0);
	int op,x,val;
	while (M--){
		op = read(); x = read();
		if (op == 1) {
			val = read();
			change(dfn[x], val);
			change(dfn[x] + 1, -val);
			if (f[x][0].start >= 1 && f[x][0].start <= N) {
			change(f[x][0].start, -val);
			change(f[x][0].start + f[x][0].siz, val);
			}
			if (f[x][1].start >= 1 && f[x][1].start <= N) {
				change(f[x][1].start, val);
				change(f[x][1].start + f[x][1].siz, -val);
			}
		}
		else {
			printf("%lld\n", ask(dfn[x]));
		}
	}
}
signed main() {
	ini();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值