题意:有长度为n的01串,设s[i]=1,s[j]=1,让你计算所有满足s[i]=1,s[j]=1且1<=i<j<=n的j-i的总和,下面有m次操作+询问,问操作前和每一次操作的答案,1<=n,m<=1e5
感想:这比赛是叫寒假**基础 **算法训练营,玩了2个小时的树状数组一直TLE,后来想想算错法时间复杂度了,看了看题解,加等数列是个什么鬼,还没怎么学,先转转大佬链接,嗯!很基础 !然后在这个加等数列的思想上套个线段树,开两个线段树维护一下[1,pos-1]和[pos+1,n]的值就行了,每加/减一个1,每棵线段树对应的区间就加/减1,每次询问的答案就是tree1[1,pos-1]+tree2[pos,n],主要还是再要一个线段树的模板
然后的话加等数列还行,反正我只会模板。。。。。如果是加等多项式的话,玩了几个小时终于放弃了,先给个加等数列的模板吧
至于为什么这么做是对的自己列两个表就知道了,如果要构造多项式,靠的还是脑子,干。
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define ld long double
#define rep1(i,n) for(int i=1;i<=n;i++)
#define rep0(i,n) for(int i=0;i<n;i++)
#define rep(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
const ll mod=1e9+7;
const int maxn=1e5+7;
int n,m,d2[maxn],l,r,a,k;
void add(int l,int r,int a,int k)
{
d2[l]+=a;
d2[l+1]+=k-a;
d2[r+1]-=(r-l+1)*k+a;
d2[r+2]-=(l-r)*k-a;
}
void pre_sum()
{
for(int i=1;i<=n;++i)
{
d2[i]+=d2[i-1];
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;++i)
{
scanf("%d %d %d %d",&l,&r,&a,&k);
add(l,r,a,k);
}
pre_sum();
pre_sum();
for(int i=1;i<=n;++i)
{
printf("%d%c",d2[i],i==n?'\n':' ');
}
return 0;
}
这里就是答案
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define ld long double
#define rep1(i,n) for(int i=1;i<=n;i++)
#define rep0(i,n) for(int i=0;i<n;i++)
#define rep(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
const ll mod=1e9+7;
const int maxn=1e5+7;
char s[maxn];
int n,m,x,q;
ll ans;
struct node
{
ll sum,lazy;
int l,r;
};
struct Segement_tree
{
node t[4*maxn];
void pushdown(int root)
{
if(t[root].lazy!=0)
{
t[root].sum+=t[root].lazy*(t[root].r-t[root].l+1);//线段树更新值
if(t[root].l!=t[root].r)
{
int ch=root<<1;
t[ch].lazy+=t[root].lazy;
t[ch+1].lazy+=t[root].lazy;
}
t[root].lazy=0;
}
}
void update(int root)
{
int ch=root<<1;
pushdown(ch);
pushdown(ch+1);
t[root].sum=t[ch].sum+t[ch+1].sum;//线段树更新值
}
void build(int l,int r,int root=1)
{
t[root].l=l,t[root].r=r;
if(l!=r)
{
int mid=(l+r)>>1,ch=root<<1;
build(l,mid,ch);
build(mid+1,r,ch+1);
update(root);//初始化每个节点的值为0
}
else t[root].sum=0;//线段树更新值
}
void change(int l,int r,ll delta,int root=1)
{
if(l==t[root].l&&r==t[root].r)
{
t[root].lazy+=delta;
pushdown(root);
return;
}
int mid=(t[root].l+t[root].r)>>1,ch=root<<1;
if(r<=mid)change(l,r,delta,ch);
else if(l>mid)change(l,r,delta,ch+1);
else {change(l,mid,delta,ch);change(mid+1,r,delta,ch+1);}
update(root);
}
ll sum(int l,int r,int root=1)
{
pushdown(root);
if(t[root].l==l&&t[root].r==r){return t[root].sum;}
int mid=(t[root].l+t[root].r)>>1;
int ch=root<<1;
if(r<=mid)return sum(l,r,ch);
else if(l>mid)return sum(l,r,ch+1);
else return sum(l,mid,ch)+sum(mid+1,r,ch+1);
}
}pre,suf;
int main()
{
// freopen("in.txt","r",stdin);
cin>>n;scanf("%s",s+1);
pre.build(1,n);
suf.build(1,n);
for(int i=1;i<=n;i++)
if(s[i]=='1')
{
ans=(ans+pre.sum(1,i))%mod;
if(i!=n)pre.change(i+1,n,1);
if(i!=1)suf.change(1,i-1,1);
}
printf("%lld\n",ans);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q,&x);
ll pres=pre.sum(1,x);
ll sufs=suf.sum(x,n);
if(q==1)
{
ans=(ans+pres+sufs)%mod;
if(x!=n)pre.change(x+1,n,1);
if(x!=1)suf.change(1,x-1,1);
}
else
{
ans=((ans-pres-sufs)%mod+mod)%mod;
if(x!=n)pre.change(x+1,n,-1);
if(x!=1)suf.change(1,x-1,-1);
}
printf("%lld\n",ans);
}
return 0;
}