【bzoj2120】数颜色【树套树+平衡树 树状数组套权值线段树】

2120: 数颜色

Description

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

Input

第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

Output

对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。


题意:有一个区间,支持两种操作:修改一个值,查询一个区间内有多少个不同的数。

可以对于每一个位置,维护pre,即这个值前面最后一次出现的位置,和sub,即这个值后面第一次出现的位置。查询[l,r]区间有多少个不同的数,就是查询[l,r]区间有多少个位置的pre<l。很显然,这个东西可以用主席树解决,询问时差分一下即可。带修改操作也真是恶心,改成树状数组套权值线段树。

再来说一下怎么维护pre和sub。要把权值离散化一下,再开n棵平衡树对应每种权值。修改时再各种乱搞,把各种贡献加加减减的,并找到新的值的pre和sub。细节详见代码。我打了一棵替罪羊树,发现还真是挺快的,第一次进RANK前3页。

坑啊!我的数组开成10000,不知怎么的就WA了一个上午!改成11000就AC了。不是应该RE的吗 = =

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
inline int rd()
{
	char ch=getchar();
	int ret=0,f=1;
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		ret=ret*10+ch-'0';
		ch=getchar();
	}
	return ret*f;
}
const int N=11005;
int n,m,cnt,a[N],hash[2*N],pre[N],sub[N],last[N],root[N];
int sumv[N*100],lc[N*100],rc[N*100],L[10005],R[10005];
int mempool[2*N],siz[2*N],tot[2*N],key[2*N],del[2*N],pos[2*N],ch[2*N][2];
struct query
{
	char s[5];
	int l,r;
}q[N];
int getid(int x)
{
	return lower_bound(hash+1,hash+hash[0]+1,x)-hash;
}
int lowbit(int x)
{
	return x&(-x);
}
struct ScapeGoatTree
{
	int root;
	int *goat;
	int rnk(int x)
	{
		int k=root,ret=1;
		while(k)
		{
			if(x<=key[k]) k=ch[k][0];
			else
			{
				ret+=siz[ch[k][0]]+del[k];
				k=ch[k][1];
			}
		}
		return ret;
	}
	int kth(int x)
	{
		if(x<1||x>siz[root]) return 0;
		int k=root;
		while(k)
		{
			if(del[k]&&x==siz[ch[k][0]]+1) return key[k];
			else if(x<=siz[ch[k][0]]+del[k]) k=ch[k][0];
			else
			{
				x-=siz[ch[k][0]]+del[k];
				k=ch[k][1];
			}
		}
	}
	void dfs(int k)
	{
		if(!k) return;
		dfs(ch[k][0]);
		if(del[k]) pos[++pos[0]]=k;
		else mempool[++mempool[0]]=k;
		dfs(ch[k][1]);
	}
	void build(int &k,int l,int r)
	{
		if(l>r)
		{
			k=0;
			return;
		}
		int mid=(l+r)/2;
		k=pos[mid];
		build(ch[k][0],l,mid-1);
		build(ch[k][1],mid+1,r);
		siz[k]=siz[ch[k][0]]+siz[ch[k][1]]+1;
		tot[k]=tot[ch[k][0]]+tot[ch[k][1]]+1;
	}
	void rebuild(int &k)
	{
		pos[0]=0;
		dfs(k);
		build(k,1,pos[0]);
	}
	void insert(int &k,int x)
	{
		if(!k)
		{
			k=mempool[mempool[0]--];
			key[k]=x;
			siz[k]=tot[k]=del[k]=1;
			ch[k][0]=ch[k][1]=0;
			return;
		}
		siz[k]++;
		tot[k]++;
		if(x<=key[k]) insert(ch[k][0],x);
		else insert(ch[k][1],x);
		if(siz[k]*0.75<max(siz[ch[k][0]],siz[ch[k][1]]))
			goat=&k;
	}
	void insert(int x)
	{
		goat=NULL;
		insert(root,x);
		if(goat) rebuild(*goat);
	}
	void remove(int k,int x)
	{
		if(del[k]&&x==siz[ch[k][0]]+1)
		{
			siz[k]--;
			del[k]=0;
			return;
		}
		siz[k]--;
		if(x<=siz[ch[k][0]]+del[k])
			remove(ch[k][0],x);
		else remove(ch[k][1],x-siz[ch[k][0]]-del[k]);
	}
	void remove(int x)
	{
		remove(root,rnk(x));
		if(siz[root]<tot[root]*0.75) rebuild(root);
	}
}sgt[N];
void update(int &o,int l,int r,int k,int v)
{
	if(!o) o=++cnt;
	sumv[o]+=v;
	if(l==r) return;
	int mid=(l+r)/2;
	if(k<=mid) update(lc[o],l,mid,k,v);
	else update(rc[o],mid+1,r,k,v);
}
int query(int l,int r,int k)
{
	if(l==r) return 0;
	int mid=(l+r)/2;
	if(k<=mid)
	{
		for(int i=1;i<=L[0];i++) L[i]=lc[L[i]];
		for(int i=1;i<=R[0];i++) R[i]=lc[R[i]];
		return query(l,mid,k);
	}
	else
	{
		int sum=0;
		for(int i=1;i<=L[0];i++)
		{
			sum-=sumv[lc[L[i]]];
			L[i]=rc[L[i]];
		}
		for(int i=1;i<=R[0];i++)
		{
			sum+=sumv[lc[R[i]]];
			R[i]=rc[R[i]];
		}
		return sum+query(mid+1,r,k);
	}
}
int solvequery(int l,int r)
{
	L[0]=R[0]=0;
	for(int i=l-1;i;i-=lowbit(i)) L[++L[0]]=root[i];
	for(int i=r;i;i-=lowbit(i)) R[++R[0]]=root[i];
	return query(0,n,l);
}
int main()
{
	for(int i=1;i<=20000;i++) mempool[i]=i;
	mempool[0]=20000;
	n=rd(),m=rd();
	for(int i=1;i<=n;i++)
		hash[++hash[0]]=a[i]=rd();
	for(int i=1;i<=m;i++)
	{
		scanf("%s",q[i].s);
		q[i].l=rd(),q[i].r=rd();
		if(q[i].s[0]=='R') hash[++hash[0]]=q[i].r;
	}
	sort(hash+1,hash+hash[0]+1);
	hash[0]=unique(hash+1,hash+hash[0]+1)-hash-1;
	for(int i=1;i<=n;i++)
	{
		a[i]=getid(a[i]);
		pre[i]=last[a[i]];
		if(last[a[i]]) sub[last[a[i]]]=i;
		last[a[i]]=i;
		sgt[a[i]].insert(i);
		for(int j=i;j<=n;j+=lowbit(j))
			update(root[j],0,n,pre[i],1);
	}
	for(int i=1;i<=m;i++)
	{
		if(q[i].s[0]=='Q')
		{
			L[0]=R[0]=0;
			for(int j=q[i].l-1;j;j-=lowbit(j)) L[++L[0]]=root[j];
			for(int j=q[i].r;j;j-=lowbit(j)) R[++R[0]]=root[j];
			printf("%d\n",query(0,n,q[i].l));
		}
		else
		{
			q[i].r=getid(q[i].r);
			for(int j=q[i].l;j<=n;j+=lowbit(j))
				update(root[j],0,n,pre[q[i].l],-1);
			if(pre[q[i].l]) sub[pre[q[i].l]]=sub[q[i].l];
			if(sub[q[i].l])
			{
				for(int j=sub[q[i].l];j<=n;j+=lowbit(j))
					update(root[j],0,n,q[i].l,-1);
				for(int j=sub[q[i].l];j<=n;j+=lowbit(j))
					update(root[j],0,n,pre[q[i].l],1);
				pre[sub[q[i].l]]=pre[q[i].l];
			}
			sgt[a[q[i].l]].remove(q[i].l);
			sgt[q[i].r].insert(q[i].l);
			a[q[i].l]=q[i].r;
			pre[q[i].l]=sgt[q[i].r].kth(sgt[q[i].r].rnk(q[i].l)-1);
			sub[q[i].l]=sgt[q[i].r].kth(sgt[q[i].r].rnk(q[i].l)+1);
			for(int j=q[i].l;j<=n;j+=lowbit(j))
				update(root[j],0,n,pre[q[i].l],1);
			if(pre[q[i].l]) sub[pre[q[i].l]]=q[i].l;
			if(sub[q[i].l])
			{
				for(int j=sub[q[i].l];j<=n;j+=lowbit(j))
					update(root[j],0,n,pre[q[i].l],-1);
				for(int j=sub[q[i].l];j<=n;j+=lowbit(j))
					update(root[j],0,n,q[i].l,1);
				pre[sub[q[i].l]]=q[i].l;
			}
		}
	}
	return 0;
}

posted @ 2017-10-22 13:49  ez_2016gdgzoi471  阅读(336)  评论(0编辑  收藏  举报