• 【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
    ",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;
    }

  • 相关阅读:
    reset password for local admin on Windows2016 by Powershell
    解决AOP嵌套失效的问题
    在SpringBoot中使用Docker(利用dockerfile-maven-plugin插件)
    Docker启动的问题解决笔记
    SpringBoot中各配置文件的优先级及加载顺序
    【转】SpringBoot启动服务的三种方式
    【转】详解springboot-修改内置tomcat版本
    Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
    SpringCloud搭建Eureka集群
    SpringCloud警告(Eureka):EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476918.html
Copyright © 2020-2023  润新知