bzoj 3809 Gty的二逼妹子序列(莫队算法,块状链表)
【题意】
回答若干个询问,(l,r,a,b):区间[l,r]内权值在[a,b]的数有多少[种]。
【思路】
考虑使用块状链表实现莫队算法中的插入与删除。
因为权值处于1..n之间,所以我们可以建一个基于权值的块状链表,每个块维护一个区间信息sum,表示权值在该块的数的种数。
这样插入与删除只需要O(1)的时间,查询需要O(sqrt(n))的时间,总的时间复杂度为O(n^1.5+qn^0.5)
【代码】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 const int N = 3e5+10; 15 16 ll read() { 17 char c=getchar(); 18 ll f=1,x=0; 19 while(!isdigit(c)) { 20 if(c=='-') f=-1; c=getchar(); 21 } 22 while(isdigit(c)) 23 x=x*10+c-'0',c=getchar(); 24 return x*f; 25 } 26 27 int n,m,B; 28 int pos[N],sum[N],cnt[N],a[N],ans[N]; 29 30 struct Node 31 { 32 int id,l,r,a,b; 33 bool operator < (const Node& rhs) const 34 { 35 return pos[l]<pos[rhs.l]||(pos[l]==pos[rhs.l]&&r<rhs.r); 36 } 37 } q[N]; 38 39 void upd(int x,int v) 40 { 41 cnt[x]+=v; 42 if(v==1&&cnt[x]==1) sum[pos[x]]++; 43 if(v==-1&&cnt[x]==0) sum[pos[x]]--; 44 } 45 int query(int l,int r) 46 { 47 int bl=pos[l],br=pos[r]; 48 int ans=0; 49 if(bl==br) 50 { 51 FOR(i,l,r) ans+=cnt[i]>0; 52 return ans; 53 } 54 FOR(i,bl+1,br-1) ans+=sum[i]; 55 bl=B*bl; 56 br=B*(br-1)+1; 57 FOR(i,l,bl) ans+=cnt[i]>0; 58 FOR(i,br,r) ans+=cnt[i]>0; 59 return ans; 60 } 61 62 int main() 63 { 64 n=read(),m=read(); 65 FOR(i,1,n) a[i]=read(); 66 B=sqrt(n+0.5); 67 FOR(i,1,n) pos[i]=(i-1)/B+1; 68 FOR(i,1,m) 69 { 70 q[i].l=read(),q[i].r=read(); 71 q[i].a=read(),q[i].b=read(); 72 q[i].id=i; 73 } 74 sort(q+1,q+m+1); 75 int l=1,r=0; 76 FOR(i,1,m) 77 { 78 while(l<q[i].l) upd(a[l++],-1); 79 while(l>q[i].l) upd(a[--l],1); 80 while(r<q[i].r) upd(a[++r],1); 81 while(r>q[i].r) upd(a[r--],-1); 82 ans[q[i].id]=query(q[i].a,q[i].b); 83 } 84 FOR(i,1,m) 85 printf("%d\n",ans[i]); 86 return 0; 87 }
posted on 2016-04-01 16:30 hahalidaxin 阅读(344) 评论(0) 编辑 收藏 举报