2020牛客寒假算法基础集训营3 G 牛牛的Link Power II(线段树)

题目链接

题目描述

牛牛有一颗大小为n的神奇Link-Cut 数组,数组上的每一个节点都有两种状态,一种为link状态,另一种为cut状态。数组上任意一对处于link状态的无序点对(即(u,v)和(v,u)被认为是同一对)会产生dis(u,v)的link能量,dis(u,v)为数组上u到v的距离。

我们定义整个数组的Link能量为所有处于link状态的节点产生的link能量之和。

一开始数组上每个节点的状态将由一个长度大小为n的01串给出,'1'表示Link状态,'0'表示Cut状态。

牛牛想要知道一开始,以及每次操作之后整个数组的Link能量,为了避免这个数字过于庞大,你只用输出答案对1e9+7取余后的结果即可。

思路

 把一个大区间分成两个小区间计算,例如:11011111,可以分开成1101和1111,那么大区间的Link值就是左边区间内的Link加右区间的Link,再加上左边区间和右边区间互相的贡献,所以可以用线段树维护一下每个区间内的Link值,左右区间互相的贡献也很好计算。

设他们的下标从1开始,那么就有

11011111
12345678

可以看出,左右两边互相的贡献就是

[(5-1)+(6-1)+(7-1)+(8-1)] +[(5-2)+(6-2)+(7-2)+(8-2)]+[(5-4)+(6-4)+(7-4)+(8-4)]

把左边区间的点的坐标和右边区间点的坐标提取出来,可以发现,结果就是

右区间所有为1 的点的下标之和rpossum乘以左边为1 的点的个数lcnt,减去左区间所有为1 的点的下标和lpossum乘以右区间为1 的点的个数rcnt,即rpossum\times lcnt-lpossum\times rcnt

因此只需要线段树去维护各区间内的为1 的点的个数和为1 的点的下标和即可,每次查询的时候更新完直接输出根节点的sum值即可(注意取模)

#include <bits/stdc++.h>
#pragma warning (disable:4996)
#pragma warning (disable:6031)
#define mem(a, b) memset(a, b, sizeof a)
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
const int mod = 1e9 + 7;
char s[N];
struct p {
	ll l, r, possum, cnt, sum;
};
struct SegementTree {
	p c[N * 4];
	SegementTree() {
		mem(c, 0);
	}
	void build(ll l, ll r, ll k) {
		c[k].l = l;
		c[k].r = r;
		c[k].possum = 0;
		c[k].sum = 0;
		c[k].cnt = 0;
		if (l == r) {
			if (s[l - 1] == '0')return ;
			c[k].cnt = 1;
			c[k].possum = l;
			c[k].sum = 0;
			return ;
		}
		ll mid = (l + r) / 2;
		build(l, mid, k << 1);
		build(mid + 1, r, k << 1 | 1);
		c[k].cnt = c[k << 1].cnt + c[k << 1 | 1].cnt;
		c[k].possum = c[k << 1].possum + c[k << 1 | 1].possum;
		c[k].sum = c[k << 1].sum + c[k << 1 | 1].sum;
		c[k].sum %= mod;
		c[k].sum += c[k << 1 | 1].possum * c[k << 1].cnt % mod - c[k << 1].possum * c[k << 1 | 1].cnt % mod;
		c[k].sum = (c[k].sum + mod) % mod;
	}
	void update1(ll ind, ll k) {
		// 0->1
		if (c[k].l == c[k].r) {
			c[k].cnt = 1;
			c[k].possum = c[k].l;
			c[k].sum = 0;
			return ;
		}
		ll mid = c[k].l + c[k].r;
		mid /= 2;
		if (ind <= mid)update1(ind, k << 1);
		else update1(ind, k << 1 | 1);
		c[k].possum = c[k << 1].possum + c[k << 1 | 1].possum;
		c[k].cnt = c[k << 1].cnt + c[k << 1 | 1].cnt;
		c[k].sum = c[k << 1].sum + c[k << 1 | 1].sum;
		c[k].sum %= mod;
		c[k].sum += c[k << 1 | 1].possum * c[k << 1].cnt % mod - c[k << 1].possum * c[k << 1 | 1].cnt % mod;
		c[k].sum = (c[k].sum + mod) % mod;
	}
	void update2(ll ind, ll k) {
		// 1->0
		if (c[k].l == c[k].r) {
			c[k].cnt = 0;
			c[k].possum = 0;
			c[k].sum = 0;
			return ;
		}
		ll mid = c[k].l + c[k].r;
		mid /= 2;
		if (ind <= mid)update2(ind, k << 1);
		else update2(ind, k << 1 | 1);
		c[k].possum = c[k << 1].possum + c[k << 1 | 1].possum;
		c[k].cnt = c[k << 1].cnt + c[k << 1 | 1].cnt;
		c[k].sum = c[k << 1].sum + c[k << 1 | 1].sum;
		c[k].sum %= mod;
		c[k].sum += c[k << 1 | 1].possum * c[k << 1].cnt % mod - c[k << 1].possum * c[k << 1 | 1].cnt % mod;
		c[k].sum = (c[k].sum + mod) % mod;
	}
};
SegementTree st;
int main()
{
	int n;
	scanf("%d", &n);
	scanf("%s", s);
	st.build(1, n, 1);
	printf("%lld\n", st.c[1].sum);
	int q;
	scanf("%d", &q);
	for (int i = 1; i <= q; i++) {
		ll a, b;
		scanf("%lld %lld", &a, &b);
		if (a == 1) {
			st.update1(b, 1);
		}
		else st.update2(b, 1);
		printf("%lld\n", st.c[1].sum);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值