标签:
对于20%的数据,N ≤ 100,M ≤ 1000;
对于40%的数据,N ≤ 3000,M ≤ 200000;
对于100%的数据,N ≤ 50000,M ≤ 200000。
头一次离线做这种题
一个显然错误的做法:直接算有几个贝壳,sb地用树状数组求01区间的前缀和
但这什么时候正确呢?
当且仅当询问的区间一种颜色只出现了一次
那么我们不妨先读进来要求的区间,按左端点排序
一个一个处理询问,这样相当于在模拟一个类似滑动窗口的东西,
当滑动窗口左边扫到一种颜色时,即这种颜色不再计算时,我们再添加下一个和它颜色相同的元素
因为同色元素位置关系是唯一的,所以在给答案加一时,询问窗口内仅存在一个一种颜色的元素
处理下一个颜色可以预处理出来,初始化时要添加每种颜色的第一个元素
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<algorithm> #define LL long long using namespace std; typedef struct{ int l,r; int ans; int pos; }qry; qry qr[200010]; int a[50050]; int now[1001000],next[50050]; int bit[50050],n; int cmp1(const qry a,const qry b){ if(a.l<b.l)return 1; else if(a.l==b.l)return a.r<b.r; else return 0; } int cmp2(const qry a,const qry b){ return a.pos<b.pos; } int lb(int x){ return x&(-x); } int c(int x){ while(x<=n){ bit[x]++; x+=lb(x); } return 0; } int q(int x){ int ans=0; while(x){ ans+=bit[x]; x-=lb(x); } return ans; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i]++;//0 if(!now[a[i]])c(i); next[now[a[i]]]=i; now[a[i]]=i; } int m; scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%d %d",&qr[i].l,&qr[i].r); qr[i].pos=i; } sort(qr+1,qr+m+1,cmp1); int l=1; for(int i=1;i<=m;i++){ //????? while(l<qr[i].l){ if(next[l])c(next[l]); l++; } qr[i].ans=q(qr[i].r)-q(qr[i].l-1); } sort(qr+1,qr+m+1,cmp2); for(int i=1;i<=m;i++)printf("%d\n",qr[i].ans); return 0; }
[bzoj1878] [SDOI2009]HH的项链(树状数组+离线)
标签:
原文地址:http://www.cnblogs.com/Pumbit-Legion/p/5874133.html