牛客 - 牛牛的Link Power II(线段树)

题目链接:点击查看

题目大意:给出一个01字符串 s ,现在规定每两个 1 的贡献为其在字符串中的距离,现在有 m 次操作,每次操作会把一个位置将 0 变成 1 或者将 1 变成 0 ,问每次操作后字符串的总贡献之和

题目分析:其实想清楚了就可以直接用线段树来维护状态,用区间合并处理一下细节就好了,假设每个节点代表着当前节点的贡献,如果相邻两个节点想要合并的话,只需要再加上相邻两个节点互相的贡献就好了,这个具体可以用平均值来解决,也就是每个节点所有 1 的下下标的平均值,因为线段树在合并时,右节点的下标一定比左节点的下标要大,所以平均下标固然也大,所以显然两个节点之间的贡献为( average_pos[ r ] - average_pos[ r ] ) * cnt[ r ] * cnt[ l ],但是下标的平均值如果直接带入会出现小数,不过我们只需要化简一步就可以避免:

( average_pos[ r ] - average_pos[ r ] ) * cnt[ r ] * cnt[ l ]

=( sum_pos[ r ] / cnt[ r ] - sum_pos[ r ] / cnt[ l ] ) * cnt[ r ] * cnt[ l ]

= sum_pos[ r ] * cnt[ l ] - sum_pos[ r ] * cnt[ r ]

其中cnt_pos是所有 1 的下标之和,这样直接转移就好了

代码:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<unordered_map>
using namespace std;
   
typedef long long LL;
  
typedef unsigned long long ull;
   
const int inf=0x3f3f3f3f;
   
const int N=1e5+100;

const int mod=1e9+7;

char s[N];

struct Node
{
	int l,r;
	LL pos_sum,cnt,ans;//pos_sum:所有位置之和 cnt:有多少个1 ans:答案 
}tree[N<<2];

void pushup(int k)
{
	tree[k].cnt=tree[k<<1].cnt+tree[k<<1|1].cnt;
	tree[k].pos_sum=tree[k<<1].pos_sum+tree[k<<1|1].pos_sum;
	tree[k].ans=(tree[k<<1].ans+tree[k<<1|1].ans+(tree[k<<1|1].pos_sum%mod*tree[k<<1].cnt%mod+mod-tree[k<<1].pos_sum%mod*tree[k<<1|1].cnt%mod)%mod)%mod;
}

void build(int k,int l,int r)
{
	tree[k].l=l;
	tree[k].r=r;
	if(l==r)
	{
		if(s[l]=='1')
		{
			tree[k].pos_sum=l;
			tree[k].cnt=1;
			tree[k].ans=0;
		}
		else
		{
			tree[k].pos_sum=tree[k].cnt=tree[k].ans=0;
		}
		return;
	}
	int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k);
}

void update(int k,int pos,int val)
{
	if(tree[k].l==tree[k].r)
	{
		if(val)
		{
			tree[k].pos_sum=pos;
			tree[k].cnt=1;
			tree[k].ans=0;
		}
		else
		{
			tree[k].pos_sum=tree[k].cnt=tree[k].ans=0;
		}
		return;
	}
	int mid=tree[k].l+tree[k].r>>1;
	if(mid>=pos)
		update(k<<1,pos,val);
	else
		update(k<<1|1,pos,val);
	pushup(k);
}

int main()
{
//#ifndef ONLINE_JUDGE
//  freopen("input.txt","r",stdin);
//    freopen("output.txt","w",stdout);
//#endif
//  ios::sync_with_stdio(false);
	int n;
	scanf("%d%s",&n,s+1);
	build(1,1,n);
	printf("%lld\n",tree[1].ans);
	int m;
	scanf("%d",&m);
	while(m--)
	{
		int op,pos;
		scanf("%d%d",&op,&pos);
		if(op==1)
			update(1,pos,1);
		else
			update(1,pos,0);
		printf("%lld\n",tree[1].ans);
	}
	
	
	
	
	

      
      
      
      
      
      
      
      
      
    return 0;
}
发布了646 篇原创文章 · 获赞 20 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/104230371