P6373 「StOI-1」IOI计数
题目大意
给定\(n,m\)代表有一长为\(n\)的只由'I'和'O'组成的字符串和\(m\)次操作。
接下来一行是长为\(n\)的字符串\(S\)
接下来\(m\)行代表\(m\)个操作,每行格式为\(1\ p\ c\)或\(2\ l\ r\),分别代表将\(p\)位置的字符改为\(c\)和查询区间\(l\)~\(r\)中有多少个个子序列为\(IOI\)
solution
甚至连口胡都不会,但是SWC神讲解过后发现是道很好的线段树板子。
对于线段树上的每个节点所表示的区间\(l\)~\(r\),维护该区间上的\(I、O、IO、OI、IOI\)的个数,将维护对象分成两部分,然后就是一段口诀:
\[I=I+I\\
O=O+O\\
IO=IO+IO+I*O\\
OI=OI+OI+O*I\\
IOI=IOI+IOI+IO*I+I*OI\\
\]
然后就做完了
代码如下(码风被SWC喷了)
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=getchar();
return x*f;
}
int n,m,gpc;
char s[500010];
struct node
{
int O,I,IO,OI,IOI;
int ls,rs;
}tr[2010000],ze;
void upd(int now)
{
tr[now].I=tr[tr[now].ls].I+tr[tr[now].rs].I;
tr[now].O=tr[tr[now].ls].O+tr[tr[now].rs].O;
tr[now].IO=tr[tr[now].ls].I*tr[tr[now].rs].O+tr[tr[now].ls].IO+tr[tr[now].rs].IO;
tr[now].OI=tr[tr[now].ls].O*tr[tr[now].rs].I+tr[tr[now].ls].OI+tr[tr[now].rs].OI;
tr[now].IOI=tr[tr[now].ls].IO*tr[tr[now].rs].I+tr[tr[now].ls].I*tr[tr[now].rs].OI+tr[tr[now].ls].IOI+tr[tr[now].rs].IOI;
return;
}
int build(int l,int r)
{
int now=++gpc;
if(l==r)
{
if(s[l]=='I')tr[now].I=1;
else tr[now].O=1;
return now;
}
int mid=(l+r)>>1;
tr[now].ls=build(l,mid);
tr[now].rs=build(mid+1,r);
upd(now);
return now;
}
void update(int rt,int l,int r,int p,char change)
{
if(l==r)
{
if(s[l]==change)return;
s[l]=change;
if(s[l]=='I')
{
tr[rt].I=1;
tr[rt].O=0;
}
if(s[l]=='O')
{
tr[rt].I=0;
tr[rt].O=1;
}
return;
}
int mid=(l+r)>>1;
if(p<=mid)update(tr[rt].ls,l,mid,p,change);
else update(tr[rt].rs,mid+1,r,p,change);
upd(rt);
return;
}
void query(int rt,int l,int r,int L,int R,node &now)
{
if(l>=L&&r<=R)
{
now=tr[rt];
return;
}
node ls,rs;
ls=rs=ze;
int mid=(l+r)>>1;
if(mid>=L)query(tr[rt].ls,l,mid,L,R,ls);
if(mid<R)query(tr[rt].rs,mid+1,r,L,R,rs);
now=(node){ls.O+rs.O,ls.I+rs.I,ls.IO+rs.IO+ls.I*rs.O,ls.OI+rs.OI+ls.O*rs.I,ls.IOI+rs.IOI+ls.I*rs.OI+ls.IO*rs.I,0,0};
return;
}
signed main()
{
n=read();m=read();
scanf("%s",s+1);
build(1,n);
for(int i=1;i<=m;i++)
{
int x=read();
if(x==1)
{
int y=read();
char z=getchar();
update(1,1,n,y,z);
}else
{
int y=read(),z=read();
node ans;
query(1,1,n,y,z,ans);
printf("%lld\n",ans.IOI);
}
}
return 0;
}//swc AK IOI
做完你就\(AKIOI\)了

浙公网安备 33010602011771号