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\)

posted @ 2021-03-26 21:58  wwlvv  阅读(129)  评论(0)    收藏  举报