bzoj 2453: 维护队列

Description

你小时候玩过弹珠吗?
小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N。为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少。当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色。但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你来寻求帮助。

Input

输入文件第一行包含两个整数N和M。
第二行N个整数,表示初始队列中弹珠的颜色。
接下来M行,每行的形式为“Q L R”或“R x c”,“Q L R”表示A想知道从队列第L个弹珠到第R个弹珠中,一共有多少不同颜色的弹珠,“R x c”表示A把x位置上的弹珠换成了c颜色。

Output

对于每个Q操作,输出一行表示询问结果。

Sample Input


2 3
1 2
Q 1 2
R 1 2
Q 1 2

Sample Output

2
1

HINT

对于100%的数据,有1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000,小朋友A不会修改超过1000次,所有颜色均用1到10^6的整数表示。

Source

2011福建集训


【教练网上分块的题解细节太多写起来太麻烦我完全实现不出啦!】

于是我用了莫队.....

多记录个时间t就行了,然后和普通莫队一样搞【糖果公园队列版】

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[10001],b[10001];
struct ask
{
     int l,r;
     int t,p;
     int x;
}as[10001];
struct change
{
     int l,x;
     int la;
}ch[10001];
int belong[10001];
int s[1000001];
bool v[10001];
int nt,sx;
int ans;
inline bool cmp1(ask x,ask y)
{
     if(belong[x.l]<belong[y.l])
          return true;
     if(belong[x.l]==belong[y.l])
     {
          if(x.r<y.r)
               return true;
          if(x.r==y.r&&x.t<y.t)
               return true;
     }
     return false;
}
inline bool cmp2(ask x,ask y)
{
     if(x.p<y.p)
          return true;
     return false;
}
inline void turn(int l)
{
     if(v[l])
     {
          s[a[l]]--;
          if(s[a[l]]==0)
               ans--;
          v[l]=false;
     }
     else
     {
          s[a[l]]++;
          if(s[a[l]]==1)
               ans++;
          v[l]=true;
     }
}
inline void adt(int t)
{
	 int loc=ch[t].l,co=ch[t].x;
	 if(v[loc])
	 {
	      s[a[loc]]--;
	      if(s[a[loc]]==0)
	           ans--;
          a[loc]=co;
          s[co]++;
          if(s[co]==1)
               ans++;
     }
     else
          a[loc]=co;
}
inline void inct(int t)
{
	 int loc=ch[t].l,co=ch[t].la;
	 if(v[loc])
	 {
	      s[a[loc]]--;
	      if(s[a[loc]]==0)
	           ans--;
          a[loc]=co;
          s[co]++;
          if(s[co]==1)
               ans++;
     }
     else
          a[loc]=co;
}
int main()
{
     int n,m;
     scanf("%d%d",&n,&m);
     int i;
     for(i=1;i<=n;i++)
     {
          scanf("%d",&a[i]);
          b[i]=a[i];
     }
     nt=sqrt(n);
     sx=(n-1)/nt+1;
     for(i=1;i<=n;i++)
          belong[i]=(i-1)/nt+1;
     int p1=0,p2=0;
     char x[4];
     for(i=1;i<=m;i++)
     {
     	  scanf("%s",x);
     	  if(x[0]=='Q')
     	  {
     	  	   p1++;
               scanf("%d%d",&as[p1].l,&as[p1].r);
               as[p1].t=p2;
               as[p1].p=p1;
          }
          else
          {
          	   p2++;
               scanf("%d%d",&ch[p2].l,&ch[p2].x);
               ch[p2].la=b[ch[p2].l];
               b[ch[p2].l]=ch[p2].x;
          }
     }
     sort(as+1,as+1+p1,cmp1);
     int l=1,r=0,t=0;
     for(i=1;i<=m;i++)
     {
          while(l<as[i].l)
          {
          	   turn(l);
		       l++;
          }
          while(l>as[i].l)
          {
               l--;
               turn(l);
          }
          while(r<as[i].r)
          {
        	   r++;
          	   turn(r);
          }
          while(r>as[i].r)
          {
               turn(r);
               r--;
          }
          while(t<as[i].t)
          {
               t++;
               adt(t);
          }
          while(t>as[i].t)
          {
               inct(t);
               t--;
          }          
          as[i].x=ans;
     }
     sort(as+1,as+1+p1,cmp2);
     for(i=1;i<=p1;i++)
          printf("%d\n",as[i].x);
     return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值