【BZOJ 2453|bzoj 2120】 2453: 维护队列 (分块+二分)

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

 

【分析】

  跟BZOJ 3343 差不多。

  对序列求一个next,next[i]表示下一个和i同颜色的是谁(如果他是最后一个的这种颜色,那么next为正无穷)

  问题转换成计算区间[l,r]里面next大于r的有多少个,单点修改。

  转化成跟BZOJ 3343 一样的模型。

  根号n分块,块内要排序。next这条链的删除和插入可以暴力枚举,因为数据范围很小。

  时间复杂度是O(q*√n log(√n)+q*n)

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<cmath>
  7 using namespace std;
  8 #define Maxn 10010
  9 #define Maxd 1000010
 10 
 11 int a[Maxn],pos[Maxn],ft[Maxn],rt[Maxn];
 12 int nt[Maxn],lt[Maxd],b[Maxn];
 13 int n;
 14 
 15 bool cmp(int x,int y) {return x>y;}
 16 
 17 void upd(int x)
 18 {
 19     for(int i=ft[x];i<=rt[x];i++) b[i]=nt[i];
 20     sort(b+ft[x],b+1+rt[x],cmp);
 21 }
 22 
 23 void change(int x,int y)
 24 {
 25     if(lt[a[x]]==x)
 26     {
 27         lt[a[x]]=nt[x];
 28     }
 29     else
 30     {
 31         for(int i=lt[a[x]];i<=n;i=nt[i]) if(nt[i]==x)
 32         {
 33             nt[i]=nt[x];
 34             upd(pos[i]);
 35             break;
 36         }
 37     }
 38     if(x<lt[y])
 39     {
 40         nt[x]=lt[y];
 41         lt[y]=x;
 42     }
 43     else
 44     {
 45         for(int i=lt[y];i<=n;i=nt[i]) if(nt[i]>x)
 46         {
 47             nt[x]=nt[i];
 48             nt[i]=x;
 49             upd(pos[i]);
 50             break;
 51         }
 52     }
 53     upd(pos[x]);
 54     a[x]=y;
 55 }
 56 
 57 int ffind(int x,int y)
 58 {
 59     int l=ft[x],r=rt[x];
 60     if(b[l]<y) return 0;
 61     while(l<r)
 62     {
 63         int mid=(l+r+1)>>1;
 64         if(b[mid]>y) l=mid;
 65         else r=mid-1;
 66     }
 67     return l-ft[x]+1;
 68 }
 69 
 70 int query(int x,int y)
 71 {
 72     int ans=0;
 73     if(pos[x]==pos[y])
 74     {
 75         for(int i=x;i<=y;i++) if(nt[i]>y) ans++;
 76     }
 77     else
 78     {
 79         for(int i=x;i<=rt[pos[x]];i++) if(nt[i]>y) ans++;
 80         for(int i=ft[pos[y]];i<=y;i++) if(nt[i]>y) ans++;
 81         for(int i=pos[x]+1;i<pos[y];i++) ans+=ffind(i,y);
 82     }
 83     return ans;
 84 }
 85 
 86 int main()
 87 {
 88     int m,sq;
 89     scanf("%d%d",&n,&m);
 90     sq=(int)ceil(sqrt((double)n));
 91     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
 92     for(int i=1;i<=Maxd;i++) lt[i]=n+1;
 93     for(int i=n;i>=1;i--) nt[i]=lt[a[i]],lt[a[i]]=i;
 94     for(int i=1;i<=n;i++) pos[i]=(i-1)/sq+1;
 95     for(int i=1;i<n;i++) if(pos[i]!=pos[i+1]) ft[pos[i+1]]=i+1,rt[pos[i]]=i;
 96     ft[1]=1;rt[pos[n]]=n;
 97     for(int i=1;i<=n;i++) b[i]=nt[i];
 98     for(int i=1;i<=pos[n];i++) sort(b+ft[i],b+1+rt[i],cmp);
 99     
100     for(int i=1;i<=m;i++)
101     {
102         char s[10];
103         int x,y;
104         scanf("%s%d%d",s,&x,&y);
105         if(s[0]=='R')
106         {
107             change(x,y);
108         }
109         else
110         {
111             printf("%d\n",query(x,y));
112         }
113     }
114     return 0;
115 }
View Code

 

2016-12-12 13:52:29

posted @ 2016-12-12 13:47  konjak魔芋  阅读(267)  评论(0编辑  收藏  举报