小Z的袜子(hose) &&作业 (莫队)

莫队:一种非常优雅的暴力,时间复杂度一般情况下是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\n",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\n",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\n",e[i].zi,e[i].mu);
72    }
73    
74 }
View Code

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\n",e[i].ans1,e[i].ans2);
102    }
103 }
View Code

猜你喜欢

转载自www.cnblogs.com/Wwb123/p/11240954.html
今日推荐