分块大法吼啊!(ಡωಡ)

虽然知道是线段树。
但是我觉得好久没搞线段树。我不会打惹过于无趣。
所以用了分块。
谁叫这题数据<=,明摆着练分块的,分块的每次操作是
然后就是经常有的:码字15分钟,debug 2小时,搞得我连模拟题都没做完。
。。。难受qwq

分块思想

把一个整体分成一块块,遍历块比遍历点快很多很多很多。。
不知道数据是不是随机的,所以把整体分成块,因为这样理论上是最快的,请自行了解~~

本题思路

首先是基本要有的
1.:代表一个块有个元素
2.:代表有个块
就是这个没处理好,害的我白提交6次,多耗费1h多时间

3.:代表第i个块里有个元素
4.:代表第i个元素在第个块里
接下来是本题的操作
5.题目思想:先打一个最开始的,照抄里面的就行,然后我们想,每把第个从变成,就会增加到其他点距离和的值(),反之,则减少点到其他点距离和的值()。
6.:代表第个块里所有点到该块左边界()的距离
7.:代表第个块里所有点到该块右边界()的距离

本题核心qwq

那么每次新来一个,不管是加还是减,都要先求出距离和,所以如何求距离和呢?
不妨画一个图,有点丑。。。。
图
红色的是修改的点
假设这个图就这么点东西:
1.两条就是
2.对于该块外的点,增加的距离和是
一.左侧:,加1是细节问题,是中间完整块的长度
二.右侧:
3.对于块内的点,直接枚举反正一个块也就
4.注意,对于修改完的红点,需要在原来的地方进行,并且同时维护那几个数组
然后就没了~~
贴上蒟蒻代码:

#include<bits/stdc++.h>
#define maxn 100010
#define Mod 1000000007
using namespace std;

int n,m,last;
long long num,sum,now,block;
string str;
bool Map[maxn];

int bll[1010],blr[1010],blv[1010],seat[maxn],blnum; 

void Build()
{
    block=sqrt(n);
    if(n%block!=0) ++block;
    if(n%block==0) blnum=n/block;
    else blnum=n/block+1;  
    for(int i=1;i<=n;++i) 
        seat[i]=(i-1)/block+1;
    for(int i=1;i<=n;++i){
        int j=str[i-1];
        if(j=='0') continue;
        ++blv[seat[i]];
        bll[seat[i]]+=i-(block*(seat[i]-1)+1);
        blr[seat[i]]+=min(block*seat[i],1LL*n)-i;
    }
}

long long Dis_sum(int x){
    long long res=0;
    long long x_l=x-(1LL*(seat[x]-1)*block+1),x_r=min(1LL*seat[x]*block,1LL*n)-x;
    if(seat[x]>1)
        for(int i=seat[x]-1;i>=1;--i){
            long long m_dis=1LL*(seat[x]-i-1)*block;
            res=(res+(x_l+m_dis+1)*blv[i]%Mod+blr[i])%Mod;
        }
    if(seat[x]<blnum)
        for(int i=seat[x]+1;i<=blnum;++i){
            long long m_dis=1LL*(i-seat[x]-1)*block;
            res=(res+(x_r+m_dis+1)*blv[i]%Mod+bll[i])%Mod;
        }
    for(int i=(seat[x]-1)*block+1;i<=min(seat[x]*block,1LL*n);++i)
        if(Map[i]==1)
            res=(res+1LL*abs(i-x))%Mod;
    return res;
}

int main(){
    scanf("%d",&n);
    cin>>str;
    Build();
    for(int i=0;i<n;++i){
        if(str[i]=='1'){
            now=(now+(i-last)*num%Mod)%Mod;
            sum=(sum+now)%Mod;
            last=i;
            num++;
            Map[i+1]=1;
        }
        else Map[i+1]=0;
    }
    printf("%lld\n",sum);
    scanf("%d",&m);
    for(int i=1;i<=m;++i){
        int opt,x;
        scanf("%d%d",&opt,&x);
        long long dis_sum=Dis_sum(x);
        if(opt==1){
            Map[x]=1;
            blv[seat[x]]++;
            bll[seat[x]]+=x-((seat[x]-1)*block+1);
            blr[seat[x]]+=min(1LL*n,seat[x]*block)-x;
            sum=(sum+dis_sum)%Mod;
            printf("%lld\n",sum);
        }
        if(opt==2){
            Map[x]=0;
            blv[seat[x]]--;
            bll[seat[x]]-=x-((seat[x]-1)*block+1);
            blr[seat[x]]-=min(seat[x]*block,1LL*n)-x;
            sum=(sum-dis_sum+1LL*100000*Mod)%Mod;
            printf("%lld\n",sum);
        }
    }
    return 0;
}

分块永远是正宫...这种思想啥都能维护(ಡωಡ)