莫队:一种非常优雅的暴力,时间复杂度一般情况下是n*根号n,还是很优秀的。
今天水了三道莫队题,对普通莫队有了些了解
1.莫队l和r为指针,维护当前区间的某些信息,一般可以是当前区间不同权值的个数,(或许可以再加些限制)
2.莫队指针移动时的操作一定是O(1)最多O(log(n)),
3.当减值时先减当前的再加,加则反。
T1
水题,维护当前区间sum[i]*sum[i]的和,在进行操作即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<cmath> 7 #include<stack> 8 #include<map> 9 #include<queue> 10 #define ps push_back 11 #define MAXN 55101 12 #define ll long long 13 using namespace std; 14 ll kuan; 15 struct node{ll l,r,id,zi,mu;}e[MAXN]; 16 ll se[MAXN],sum[MAXN]; 17 bool cmp(node a,node b) 18 { 19 return ((a.l/kuan)!=(b.l/kuan))?(a.l<b.l):(a.r<b.r); 20 } 21 bool CMP(node a,node b) 22 { 23 return a.id<b.id; 24 } 25 ll n,m;ll ans=0; 26 void jian(ll x) 27 { 28 ans-=sum[se[x]]*sum[se[x]];sum[se[x]]--;ans+=sum[se[x]]*sum[se[x]]; 29 } 30 void add(ll x) 31 { 32 ans-=sum[se[x]]*sum[se[x]];sum[se[x]]++;ans+=sum[se[x]]*sum[se[x]]; 33 } 34 ll gcd(ll a,ll b) 35 { 36 return (b==0)?a:gcd(b,a%b); 37 } 38 int main() 39 { 40 scanf("%lld%lld",&n,&m);kuan=sqrt(n); 41 for(ll i=1;i<=n;++i) 42 { 43 ll x; 44 scanf("%lld",&se[i]); 45 } 46 for(ll i=1;i<=m;++i) 47 { 48 ll l,r; 49 scanf("%lld%lld",&e[i].l,&e[i].r); 50 e[i].id=i; 51 } 52 sort(e+1,e+m+1,cmp); 53 ll l=1,r=0; 54 for(ll i=1;i<=m;++i) 55 { 56 //printf("l=%lld e[i].l=%lld r=%lld e[i].r=%lld ",l,e[i].l,r,e[i].r); 57 while(l<e[i].l){jian(l++);} 58 while(l>e[i].l){add(--l);} 59 while(r<e[i].r){add(++r);} 60 while(r>e[i].r){jian(r--);} 61 e[i].zi=ans-(e[i].r-e[i].l+1); 62 e[i].mu=(e[i].r-e[i].l+1)*(e[i].r-e[i].l); 63 if(e[i].zi==0){e[i].mu=1;continue;} 64 ll gcdd=gcd(e[i].zi,e[i].mu); 65 e[i].zi/=gcdd;e[i].mu/=gcdd; 66 //printf("%lld %lld ",e[i].zi,e[i].mu); 67 } 68 sort(e+1,e+m+1,CMP); 69 for(ll i=1;i<=m;++i) 70 { 71 printf("%lld/%lld ",e[i].zi,e[i].mu); 72 } 73 74 }
T2
树状数组一个维护当前区间中<=某个数的个数
一个维护<=某个数出现的不同权值的个数
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<cmath> 7 #include<stack> 8 #include<map> 9 #include<queue> 10 #define ps push_back 11 #define MAXN 205101 12 #define ll long long 13 using namespace std; 14 struct node{int l,r,id,A,B,ans1,ans2;}e[10*MAXN]; 15 int kuan;int se[MAXN],c[MAXN]; 16 bool cmp(node a,node b){return (a.l/kuan!=b.l/kuan)?(a.l<b.l):(a.r<b.r);} 17 bool CMP(node a,node b){return a.id<b.id;} 18 int lowbit(int x){return x&(-x);}int n,m; 19 void shu_add(int x,int k) 20 { 21 for(int i=x;i<=n;i+=lowbit(i)) 22 { 23 c[i]+=k; 24 } 25 } 26 int get_sum(int x) 27 { 28 int ans=0; 29 for(int i=x;i>=1;i-=lowbit(i)) 30 { 31 ans+=c[i]; 32 } 33 return ans; 34 } 35 int d[MAXN];int sum[MAXN]; 36 void shu_cishu(int x,int k) 37 { 38 for(int i=x;i<=n;i+=lowbit(i)) 39 { 40 d[i]+=k; 41 } 42 } 43 int get_sum_cishu(int x) 44 { 45 int ans=0; 46 for(int i=x;i>=1;i-=lowbit(i)) 47 { 48 ans+=d[i]; 49 } 50 return ans; 51 } 52 void add(int x) 53 { 54 if(sum[se[x]]==0) 55 { 56 shu_cishu(se[x],1); 57 } 58 sum[se[x]]++; 59 shu_add(se[x],1); 60 } 61 void jian(int x) 62 { 63 sum[se[x]]--; 64 if(sum[se[x]]==0) 65 { 66 shu_cishu(se[x],-1); 67 } 68 shu_add(se[x],-1); 69 } 70 int main() 71 { 72 scanf("%d%d",&n,&m); 73 kuan=sqrt(n); 74 for(int i=1;i<=n;++i) 75 { 76 scanf("%d",&se[i]); 77 } 78 for(int i=1;i<=m;++i) 79 { 80 scanf("%d%d%d%d",&e[i].l,&e[i].r,&e[i].A,&e[i].B); 81 if(e[i].r>n)e[i].r=n; 82 if(e[i].A>n)e[i].A=n; 83 if(e[i].B>n)e[i].B=n; 84 e[i].id=i; 85 } 86 sort(e+1,e+m+1,cmp); 87 int l=1,r=0; 88 for(int i=1;i<=m;++i) 89 { 90 while(l<e[i].l){jian(l++);} 91 while(l>e[i].l){add(--l);} 92 while(r<e[i].r){add(++r);} 93 while(r>e[i].r){jian(r--);} 94 int A=e[i].A,B=e[i].B; 95 e[i].ans1=get_sum(B)-((A-1!=0)?get_sum(A-1):0); 96 e[i].ans2=get_sum_cishu(B)-((A-1!=0)?get_sum_cishu(A-1):0); 97 } 98 sort(e+1,e+m+1,CMP); 99 for(int i=1;i<=m;++i) 100 { 101 printf("%d %d ",e[i].ans1,e[i].ans2); 102 } 103 }