首页 > 代码库 > bzoj 2453 : 维护队列 带修莫队

bzoj 2453 : 维护队列 带修莫队

 

2453: 维护队列

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 952  Solved: 432
[Submit][Status][Discuss]

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福建集训

 

  把询问和修改分开排序,修改按时间排,询问以左端点所在块为第一关键字,右端点所在块为第二关键字,时间为第三关键字排序。

  维护左右时间三个指针,不断修改还原。

  块大小为$n^{\frac{2}{3}}$。

  左指针每个询问走$n^{\frac{2}{3}}$。

  右指针同理,不过要多上每次总从左走到右的复杂度,总共$n\times n^{\frac{2}{3}}+n\times n^{\frac{1}{3}}$。

  时间指针每次左右端点所在块变化重新开始走,一共$n^{\frac{2}{3}}$个不同的左右块匹配数,复杂度$n\times n^{\frac{2}{3}}$.

  好像块开100比较快。

  

  1 #include<iostream>  2 #include<cstdio>  3 #include<cstring>  4 #include<algorithm>  5 #define d 100  6 #define N 10005  7 using namespace std;  8 int n,m;  9 int c[N]; 10 struct node 11 { 12     int l,r,t,pr; 13     node(){l=r=t=0;} 14 }q[N],g[N]; 15 int cnt1,cnt2; 16 bool cmp1(const node &aa,const node &bb) 17 { 18     return aa.t<bb.t; 19 } 20 int be1[N],be2[N]; 21 bool cmp2(const node &aa,const node &bb) 22 { 23     if(be1[aa.l]==be1[bb.l]) 24     { 25         if(be2[aa.r]==be2[bb.r])return aa.t<bb.t; 26         return aa.r<bb.r; 27     } 28     return aa.l<bb.l; 29 } 30 int ans[N]; 31 int now[N*100],cnt; 32 void solve() 33 { 34     int p1,p2,p; 35     memset(now,0,sizeof(now)); 36     now[c[1]]=1;cnt=1;g[cnt1+1].t=10005; 37     p=p1=1; 38     p2=0; 39     for(int i=1;i<=cnt2;i++) 40     { 41         while(g[p2+1].t<q[i].t) 42         { 43             p2++; 44             int tmp=c[g[p2].l]; 45             g[p2].pr=tmp; 46             c[g[p2].l]=g[p2].r; 47             if(g[p2].l<=p&&g[p2].l>=p1) 48             { 49                 now[tmp]--; 50                 if(!now[tmp])cnt--; 51                 now[g[p2].r]++; 52                 if(now[g[p2].r]==1)cnt++; 53             } 54         } 55         while(g[p2].t>q[i].t) 56         { 57              58             c[g[p2].l]=g[p2].pr; 59             if(g[p2].l<=p&&g[p2].l>=p1) 60             { 61                 now[g[p2].r]--; 62                 if(!now[g[p2].r])cnt--; 63                 now[g[p2].pr]++; 64                 if(now[g[p2].pr]==1)cnt++; 65             } 66             p2--; 67         } 68         while(p<q[i].r) 69         { 70             p++;now[c[p]]++; 71             if(now[c[p]]==1)cnt++; 72         } 73         while(p>q[i].r) 74         { 75             now[c[p]]--;if(!now[c[p]])cnt--; 76             p--; 77         } 78         while(p1<q[i].l) 79         { 80             now[c[p1]]--;if(!now[c[p1]])cnt--; 81             p1++; 82         } 83         while(p1>q[i].l) 84         { 85             p1--;now[c[p1]]++; 86             if(now[c[p1]]==1)cnt++; 87         } 88         ans[q[i].t]=cnt; 89     } 90 } 91 int main() 92 { 93     scanf("%d%d",&n,&m); 94     for(int i=1;i<=n;i++)scanf("%d",&c[i]); 95     for(int i=1;i<=n;i++) 96     { 97         be1[i]=be2[i]=(i-1)/d+1; 98     } 99     memset(ans,-1,sizeof(ans));100     char s[2];101     for(int i=1;i<=m;i++)102     {103         scanf("%s",s);104         if(s[0]==R)105         {106             cnt1++;107             scanf("%d%d",&g[cnt1].l,&g[cnt1].r);108             g[cnt1].t=i;109         }110         else111         {112             cnt2++;113             scanf("%d%d",&q[cnt2].l,&q[cnt2].r);114             q[cnt2].t=i;115         }116     }117     sort(q+1,q+cnt2+1,cmp2);118     sort(g+1,g+cnt1+1,cmp1);119     solve();120     for(int i=1;i<=m;i++)121     {122         if(ans[i]!=-1)printf("%d\n",ans[i]);123     }124     return 0;125 }

 

 

bzoj 2453 : 维护队列 带修莫队