[BZOJ2120]数颜色

bzoj
luogu

sol

树状数组套线段数题解。
对每个位置记一个\(last_i\),表示与这个位置颜色相同的前一个位置。若这个位置上的颜色是第一次出现则\(last_i=0\)
那么查询的时候就查询所有\(L\le i\le R\)\(last_i<L\)的个数就行了。
问题转化为一个二维数点问题,静态主席树动态树套树。
因为修改会影响到前趋后继什么的,所以对每个颜色开一个\(set\)然后大力讨论一波。

code

#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 1e4+5;
struct segment_tree{int ls,rs,v;}t[N*150];
int n,m,a[N],lst[N],rt[N],tot;
set<int>S[N*100];
set<int>::iterator it,itt;
void Modify(int &x,int l,int r,int p,int v)
{
	if (!x) x=++tot;t[x].v+=v;
	if (l==r) return;int mid=l+r>>1;
	if (p<=mid) Modify(t[x].ls,l,mid,p,v);
	else Modify(t[x].rs,mid+1,r,p,v);
}
int Query(int x,int l,int r,int ql,int qr)
{
	if (!x||l>=ql&&r<=qr) return t[x].v;
	int mid=l+r>>1;
	if (qr<=mid) return Query(t[x].ls,l,mid,ql,qr);
	if (ql>mid) return Query(t[x].rs,mid+1,r,ql,qr);
	return Query(t[x].ls,l,mid,ql,qr)+Query(t[x].rs,mid+1,r,ql,qr);
}
void PreModify(int k,int p,int v)
{
	for (int i=k+1;i<=n;i+=i&-i)
		Modify(rt[i],1,n,p,v);//树状数组的下标必须从1开始,所以这里选择加了一个1
}
int main()
{
	n=gi();m=gi();
	for (int i=1;i<=n;++i) a[i]=gi(),S[a[i]].insert(i);
	for (int i=1;i<=n;++i)
	{
		it=S[a[i]].find(i);
		if (it!=S[a[i]].begin()) PreModify(*--it,i,1);
		else PreModify(0,i,1);
	}
	while (m--)
	{
		char ch=getchar();
		while (ch!='Q'&&ch!='R') ch=getchar();
		if (ch=='Q')
		{
			int l=gi(),r=gi(),res=0;
			for (int i=l;i;i-=i&-i)
				res+=Query(rt[i],1,n,l,r);
			printf("%d\n",res);
		}
		else
		{
			int i=gi();
			it=S[a[i]].find(i);
			itt=it;--itt;
            if (it!=S[a[i]].begin()) PreModify(*itt,*it,-1);
			else PreModify(0,*it,-1);
            itt=it;++itt;
            if (itt!=S[a[i]].end())
			{
				PreModify(*it,*itt,-1);
				if (it!=S[a[i]].begin()) PreModify(*--it,*itt,1);
				else PreModify(0,*itt,1);
			}
			S[a[i]].erase(i);
			a[i]=gi();
			S[a[i]].insert(i);
			it=S[a[i]].find(i);
			itt=it;--itt;
			if (it!=S[a[i]].begin()) PreModify(*itt,*it,1);
			else PreModify(0,*it,1);
			itt=it;++itt;
			if (itt!=S[a[i]].end())
			{
				PreModify(*it,*itt,1);
				if (it!=S[a[i]].begin()) PreModify(*--it,*itt,-1);
				else PreModify(0,*itt,-1);
			}
		}
	}
	return 0;
}
posted @ 2018-03-14 16:41  租酥雨  阅读(147)  评论(0编辑  收藏  举报