zoukankan      html  css  js  c++  java
  • 【国家集训队2011】数颜色 (莫队)

    题面

    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支画笔中共有几种不同颜色的画笔。

    Sample Input

    6 5
    1 2 3 4 5 5
    Q 1 4
    Q 2 6
    R 1 2
    Q 1 4
    Q 2 6

    Sample Output

    4
    4
    3
    4

    Hint

    【数据规模和约定】
    对于40%数据,只包含第一类操作(无修改操作),且除此之外的20%的数据,N,M≤1000  对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。  时间限制:0.6s

    题解

    带修改莫队的模板题
    (是不是数据比较水???)
    看到两种AC做法
    一种是对于每一次修改与修改之间的询问进行莫队计算,然后更新颜色,继续算答案直到下一次修改。
    另一种是读入所有的询问,同普通莫队一样做,每次做之前更新颜色(记录当前的最后一次修改操作)。
    我用的是第二种方法。

    存颜色的修改的时候要存下修改成什么颜色以及原来的颜色(这个颜色也是会变的)
    然后和普通莫队相差就不大了。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<algorithm>
    using namespace std;
    #define MAX 2000000
    inline int read()
    {
    	register int x=0,t=1;
    	register char ch=getchar();
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-'){t=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
    	return x*t;
    }
    struct Query
    {
    	int l,r,id,t,ch;
    }q[MAX];
    struct Change
    {
    	int x,c,q;
    }cc[MAX];
    inline bool cmp(Query a,Query b)
    {
    	if(a.t==b.t)return a.r<b.r;
    	return a.t<b.t;
    }
    int n,m,m1,m2,a[MAX],A[MAX],Ans=0;
    int c[MAX],tot[MAX];
    inline void change(int sw,int ne,int l,int r)
    {
    	if(sw==ne)return;
    	if(sw<ne)
    		for(int i=sw+1;i<=ne;++i)
    		{
    			if(cc[i].x<l||cc[i].x>r)c[cc[i].x]=cc[i].c;//直接修改
    			else
    			{
    				tot[c[cc[i].x]]--;
    				if(tot[c[cc[i].x]]==0)Ans--;
    				tot[cc[i].c]++;
    				if(tot[cc[i].c]==1)Ans++;
    				c[cc[i].x]=cc[i].c;
    			}
    		}
    	if(sw>ne)
    		for(int i=sw;i>ne;--i)
    		{
    			if(cc[i].x<l||cc[i].x>r)c[cc[i].x]=cc[i].q;//直接修改
    			else
    			{
    				tot[c[cc[i].x]]--;
    				if(tot[c[cc[i].x]]==0)Ans--;
    				tot[cc[i].q]++;
    				if(tot[cc[i].q]==1)Ans++;
    				c[cc[i].x]=cc[i].q;
    			}
    		}
    }
    inline void count(int p,int kk)
    {
    	tot[c[p]]+=kk;
    	if(tot[c[p]]==0&&kk==-1)Ans--;
    	if(tot[c[p]]==1&&kk==1 )Ans++;
    }
    int main()
    {
        cin>>n>>m;
    	int Len=sqrt(n);
    	for(int i=1;i<=n;++i)cin>>a[i];
    	for(int i=1;i<=n;++i)c[i]=a[i];
    	for(int i=1;i<=m;++i)
    	{
    		char ch;int x,y;
    		cin>>ch>>x>>y;
    		if(ch=='Q')
    		{
    			m1++;
    			q[m1]=(Query){x,y,m1,(x-1)/Len+1,m2};
    		}
    		else
    		{
    			m2++;
    			cc[m2]=(Change){x,y,c[x]};
    			c[x]=y;
    		}
    	}
    	for(int i=1;i<=n;++i)c[i]=a[i];
    	sort(&q[1],&q[m1+1],cmp);
    	int l=1,r=0,sw=0;
    	for(int i=1;i<=m1;++i)
    	{
    		if(sw!=q[i].ch)change(sw,q[i].ch,l,r);
    		while(l<q[i].l)count(l-0,-1),l++;
    		while(l>q[i].l)count(l-1,+1),l--;
    		while(r<q[i].r)count(r+1,+1),r++;
    		while(r>q[i].r)count(r+0,-1),r--;
    		A[q[i].id]=Ans;
    		sw=q[i].ch;
    	}
    	for(int i=1;i<=m1;++i)
    		printf("%d
    ",A[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    堆和栈的区别 (转贴)
    Linux常用的网络命令
    H.264的编解码流程
    链表逆序
    快速排序
    一个计算机硕士毕业生的求职经验(五)
    H.264简单总结
    重要的热键 【Tab】,【Ctrl】—C,【Ctrl】—D
    Linux 文件与目录管理
    一个计算机硕士毕业生的求职经验(六)
  • 原文地址:https://www.cnblogs.com/cjyyb/p/7383934.html
Copyright © 2011-2022 走看看