bzoj 5016 [Snoi2017]一个简单的询问

题面

https://www.lydsy.com/JudgeOnline/problem.php?id=5016

题解

莫队算法

因此我们可以用(l,r) 表示ask(1,l,1,r) 然后就可以了莫队了

用num1,num2两个数组记录下当前两个区间中每个数字分别出现多少次

Code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 
 5 ll read(){
 6     ll x=0,f=1;char c=getchar();
 7     while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
 8     while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
 9     return x*f;
10 }
11 
12 const int maxn=50050;
13 const int sz=250;
14 int n;
15 int a[maxn];
16 int Q,tot;
17 struct query{
18     int l,r,id,ad;
19     bool operator < (query ano) const{
20         if(l/sz==ano.l/sz) return r<ano.r;
21         else return l<ano.l;
22     }
23 } q[maxn*10];
24 
25 inline void add(int l,int r,int id,int ad){
26     q[++tot].l=l,q[tot].r=r;
27     q[tot].id=id,q[tot].ad=ad;
28 }
29 int num1[maxn],num2[maxn],ans[maxn];
30 
31 int main(){
32 #ifdef LZT
33     freopen("in","r",stdin);
34 #endif
35     n=read();
36     for(int i=1;i<=n;i++) a[i]=read();
37     Q=read();
38     for(int i=1;i<=Q;i++){
39         int l1,r1,l2,r2;
40         l1=read(),r1=read(),l2=read(),r2=read();
41         add(r1,r2,i,1);
42         add(l1-1,r2,i,-1);
43         add(r1,l2-1,i,-1);
44         add(l1-1,l2-1,i,1);
45     }
46     sort(q+1,q+tot+1);
47     int L=0,R=0,res=0;
48     for(int i=1;i<=tot;i++){
49         while(L<q[i].l){L++;res+=num2[a[L]];num1[a[L]]++;}
50         while(L>q[i].l){res-=num2[a[L]];num1[a[L]]--;L--;}
51         while(R<q[i].r){R++;res+=num1[a[R]];num2[a[R]]++;}
52         while(R>q[i].r){res-=num1[a[R]];num2[a[R]]--;R--;}
53         ans[q[i].id]+=res*q[i].ad;
54     }
55     for(int i=1;i<=Q;i++)
56         printf("%d\n",ans[i]);
57     return 0;
58 }
59 
60 /*
61 5
62 1 1 1 1 1
63 2
64 1 2 3 4
65 1 1 4 4
66 */
View Code

Review

这样做的动机?

(数据范围50000=>应该用$O(n \sqrt n)$的做法=>莫队)

(可离线的区间问题=>莫队)

应该不算难想到

猜你喜欢

转载自www.cnblogs.com/wawawa8/p/9372746.html