ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【ybtoj高效进阶 21280】景点距离(DP)(换根)

2021-10-27 07:32:21  阅读:173  来源: 互联网

标签:rt return 进阶 int ybtoj read 21280 now op


景点距离

题目链接:ybtoj高效进阶 21280

题目大意

给你一个线段树结构的树,要你支持一下操作:
删除一条边,或者判断当前有多少对点仍然连通。

思路

既然是树,我们考虑通过树来搞,而且还是线段树,就告诉我们它的深度是 \(\log\) 级别的,可以每次枚举。

而且!我们发现 \(k\) 最大 \(40\),可以只用维护 \(1\sim 40\) 的答案。
那你考虑一开始的答案是可以直接 \(1600n\) 的复杂度暴力求出。
然后求的过程中自然是 DP,自然要设 \(f_{i,j}\) 为 \(i\) 的子树内有多少个点到 \(i\) 路径为 \(j\)。不过 \(k\) 只有 \(40\),所以第二维只用开到 \(40\)。

接着考虑修改的贡献。
你修改了之后,你把那条跑找到,它两段为根,求出对于的 \(f\)了,那想上面一样匹配一下,就是减小的贡献数。
那在下面的那个还好,它就相当于它子树的根,但上面的那个就不行。
不过我们换根 DP 一下,移一下去,修改完之后移上来就可以了。

代码

#include<cstdio>
#include<cstring>
#define ll long long
#define rr register

using namespace std;

int n, m, x, rre;
ll a[200005][41];
ll ans[41], answer;
bool kl[200005];
char op, c;

int read() {
	rre = 0;
	c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') {
		rre = (rre << 3) + (rre << 1) + c - '0';
		c = getchar();
	}
	return rre;
}

void write(ll x) {
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

void dfs(int now) {//dfs 求出以 1 为根的
	if (now > n) return ;
	
	dfs(now << 1); dfs(now << 1 | 1);
	a[now][0] = 1;
	for (int i = 1; i <= 40; i++)
		a[now][i] = a[now << 1][i - 1] + a[now << 1 | 1][i - 1];
	
	for (int i = 1; i <= 40; i++)
		ans[i] += a[now][i];
	for (int i = 0; i <= 38; i++)
		for (int j = 0; i + j <= 38; j++)
			ans[i + j + 2] += a[now << 1][i] * a[now << 1 | 1][j];
}

void up(int now, int fr) {//更新影响
	if (!now) return ;
	if (kl[fr]) return ;
	memset(a[now], 0, sizeof(a[now]));
	a[now][0] = 1;
	if (!kl[now << 1] && !kl[now << 1 | 1]) {
		for (int i = 1; i <= 40; i++)
			a[now][i] = a[now << 1][i - 1] + a[now << 1 | 1][i - 1];
	}
	else if (!kl[now << 1]) {
		for (int i = 1; i <= 40; i++)
			a[now][i] = a[now << 1][i - 1];
	}
	else if (!kl[now << 1 | 1]) {
		for (int i = 1; i <= 40; i++)
			a[now][i] = a[now << 1 | 1][i - 1];
	}
	up(now >> 1, now);
}

void down_rt(int now, int fr) {//换根
	if (!now) return ;
	if (kl[fr]) return ;
	down_rt(now >> 1, now);
	for (int i = 1; i <= 40; i++)
		a[now][i] -= a[fr][i - 1];
	for (int i = 1; i <= 40; i++)
		a[fr][i] += a[now][i - 1];
}

void up_rt(int now, int fr) {
	if (!now) return ;
	if (kl[fr]) return ;
	for (int i = 1; i <= 40; i++)
		a[fr][i] -= a[now][i - 1];
	for (int i = 1; i <= 40; i++)
		a[now][i] += a[fr][i - 1];
	up_rt(now >> 1, now);
}

int main() {
//	freopen("dis.in", "r", stdin);
//	freopen("dis.out", "w", stdout);
	
	n = read(); m = read();
	
	dfs(1);
	
	while (m--) {
		op = getchar();
		while (op != '-' && op != '?') op = getchar();
		
		x = read();
		if (op == '?') {
			answer = 0;
			for (int i = 1; i <= x; i++)
				answer += ans[i];
			write(answer); putchar('\n');
		}
		if (op == '-') {
			if (kl[x ^ 1]) {
				memset(a[x >> 1], 0, sizeof(a[x >> 1]));
				a[x >> 1][0] = 1;
			}
			else {
				a[x >> 1][0] = 1;
				for (int i = 1; i <= 40; i++)
					a[x >> 1][i] = a[x ^ 1][i - 1];
			}
			up(x >> 2, x >> 1);
			
			down_rt(x >> 2, x >> 1);
			
			for (int i = 0; i <= 39; i++)//减去贡献
				for (int j = 0; i + j <= 39; j++)
					ans[i + j + 1] -= a[x][i] * a[x >> 1][j];
			
			up_rt(x >> 2, x >> 1);
			
			kl[x] = 1;
		}
	}
	
	return 0;
}

标签:rt,return,进阶,int,ybtoj,read,21280,now,op
来源: https://www.cnblogs.com/Sakura-TJH/p/YBTOJ_GXJJ_21280.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有