NewTrain1 T1: [HEOI2012]采花
题目分析
观察题目,我们要实现一段区间的查找并且这个查找很容易用数组来维护,所以自然有一种很暴力的莫队做法。
但数据量最大为2e6,明显以 O(N*N1/2)是不够的。
继续思考,我们发现一种颜色的花若有贡献,可以仅仅把这个贡献算在区间的最后一朵花上。所以,我们把询问离线下来,按l为第一关键字,r为第二关键字排序。
用树状数组维护某个位置上的花有没有贡献。我们先把整个序列所有颜色出现第二次的位置加上1,用一个now_pos表示现在区间的左端点到哪了。随着我们从左往右递推(while now_pos<q[i].l ),每看到一朵花,那么这样做(指先加1)说明这朵花的下一朵是在产生贡献的,而当前这朵花要不在询问区间中了,说明该种颜色现在产生贡献的是该种颜色颜色的下一朵花的下一朵花,所以把下一朵该颜色的花位置上-1(它不再产生贡献),把下一朵的下一朵改颜色的花上位置+1。
然后查询就变成了树状数组上的查询,查询位置在 l~r 间有多少1即可。
先贴个莫队(可以过绝大多数点)
1 #include<bits/stdc++.h> 2 #define INTMAX 2147483647LL 3 #define PII pair<int,int> 4 #define MK make_pair 5 #define re register 6 using namespace std; 7 typedef long long ll; 8 const double Pi=acos(-1.0); 9 const int Inf=0x3f3f3f3f; 10 const int MAXN=2e6+10; 11 12 inline int read(){ 13 re int x=0,f=1,ch=getchar(); 14 while(!isdigit(ch))f=ch=='-'?-1:1,ch=getchar(); 15 while(isdigit(ch))x=x*10+ch-48,ch=getchar(); 16 return x*f; 17 } 18 inline ll readll(){ 19 re ll x=0,f=1,ch=getchar(); 20 while(!isdigit(ch))f=ch=='-'?-1:1,ch=getchar(); 21 while(isdigit(ch))x=x*10+ch-48,ch=getchar(); 22 return x*f; 23 } 24 25 struct Query{ 26 int l,r,id; 27 int l_id; 28 }q[MAXN]; 29 int n,m,c,len; 30 int a[MAXN]; 31 int cnt[MAXN],tot; 32 int ans[MAXN]; 33 inline bool cmp(Query x,Query y){ 34 return x.l_id==y.l_id?x.r<y.r:x.l_id<y.l_id; 35 } 36 int main(){ 37 n=read();c=read();m=read(); 38 len=(int)pow(n,0.66667); 39 for(re int i=1;i<=n;++i) a[i]=read(); 40 for(re int i=1;i<=m;++i){ 41 q[i].l=read(); 42 q[i].r=read(); 43 if(q[i].r<q[i].l) swap(q[i].l,q[i].r); 44 q[i].id=i;q[i].l_id=(q[i].l-1)/len+1; 45 } 46 sort(q+1,q+m+1,cmp); 47 int curL=1,curR=0; 48 for(re int i=1,l,r;i<=m;++i){ 49 l=q[i].l;r=q[i].r; 50 while(curL>l) tot+=(++cnt[a[--curL]])==2?1:0; 51 while(curR<r) tot+=(++cnt[a[++curR]])==2?1:0; 52 while(curL<l) tot-=(--cnt[a[curL++]])==1?1:0; 53 while(curR>r) tot-=(--cnt[a[curR--]])==1?1:0; 54 ans[q[i].id]=tot; 55 } 56 for(re int i=1;i<=m;++i) 57 printf("%d\n",ans[i]); 58 return 0; 59 }
然后是树状数组
1 #include<bits/stdc++.h> 2 #define INTMAX 2147483647LL 3 #define PII pair<int,int> 4 #define MK make_pair 5 #define re register 6 using namespace std; 7 typedef long long ll; 8 const double Pi=acos(-1.0); 9 const int Inf=0x3f3f3f3f; 10 const int MAXN=2e6+10; 11 inline int read(){ 12 re int x=0,f=1,ch=getchar(); 13 while(!isdigit(ch))f=ch=='-'?-1:1,ch=getchar(); 14 while(isdigit(ch))x=x*10+ch-48,ch=getchar(); 15 return x*f; 16 } 17 inline ll readll(){ 18 re ll x=0,f=1,ch=getchar(); 19 while(!isdigit(ch))f=ch=='-'?-1:1,ch=getchar(); 20 while(isdigit(ch))x=x*10+ch-48,ch=getchar(); 21 return x*f; 22 } 23 24 struct Query{ 25 int l,r,id; 26 }q[MAXN]; 27 inline bool cmp(Query x,Query y){ 28 return x.l==y.l?x.r<y.r:x.l<y.l; 29 } 30 31 int n,c,m; 32 int BIT[MAXN],ans[MAXN]; 33 int a[MAXN],nxt[MAXN],nnxt[MAXN],col[MAXN]; 34 inline int lowbit(int x){ 35 return x&(-x); 36 } 37 inline void Update(int x,int v){ 38 for(int i=x;i<=n;i+=lowbit(i)) BIT[i]+=v; 39 } 40 inline int Ask(int x){ 41 int res=0; 42 for(int i=x;i;i-=lowbit(i)) 43 res+=BIT[i]; 44 return res; 45 } 46 int main(){ 47 n=read();c=read();m=read(); 48 for(int i=1;i<=n;++i) a[i]=read(); 49 for(int i=n;i>=1;--i){ 50 nxt[i]=col[a[i]]; 51 col[a[i]]=i; 52 } 53 for(int i=1;i<=n;++i) 54 nnxt[i]=nxt[nxt[i]]; 55 memset(col,0,sizeof(col)); 56 for(int i=1;i<=n;++i) 57 if(++col[a[i]]==2) 58 Update(i,1); 59 for(int i=1;i<=m;++i){ 60 q[i].l=read();q[i].r=read();q[i].id=i; 61 } 62 sort(q+1,q+m+1,cmp); 63 int now_pos=1; 64 for(int i=1;i<=m;++i){ 65 while(now_pos<q[i].l){ 66 if(nxt[now_pos]) Update(nxt[now_pos],-1); 67 if(nnxt[now_pos]) Update(nnxt[now_pos],1); 68 ++now_pos; 69 } 70 ans[q[i].id]=Ask(q[i].r)-Ask(q[i].l-1); 71 } 72 for(int i=1;i<=m;++i) 73 printf("%d\n",ans[i]); 74 return 0; 75 }