题目链接:点击查看
题目大意:给出一个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;
}