1. 程式人生 > >專題訓練之莫隊算法

專題訓練之莫隊算法

cnblogs def class 表白 one nbsp true 能量 sum

推薦博客/專欄:https://blog.csdn.net/xianhaoming/article/details/52201761莫隊算法講解(含樹上莫隊)

https://blog.csdn.net/hzj1054689699/article/details/51866615莫隊算法

https://zhuanlan.zhihu.com/p/25017840莫隊算法

例題及講解:(BZOJ2038)https://www.luogu.org/problemnew/show/P1494

講解:https://www.cnblogs.com/MashiroSky/p/5914637.html

https://blog.csdn.net/xym_csdn/article/details/50889293

技術分享圖片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 typedef long long ll;
 7 const ll maxn=5e4+10;
 8 struct node{
 9     ll l,r,id,belong;
10     ll a,b;
11 }arr[maxn];
12 ll num[maxn],a[maxn],ans;
13 
14 bool cmp1(node a,node b)
15 { 16 if ( a.belong==b.belong ) return a.r<b.r; 17 return a.belong<b.belong; 18 } 19 20 bool cmp2(node a,node b) 21 { 22 return a.id<b.id; 23 } 24 25 ll gcd(ll x,ll y) 26 { 27 if ( y==0 ) return x; 28 return gcd(y,x%y); 29 } 30 31 void update(ll p,ll val) 32 { 33 ans-=num[a[p]]*num[a[p]];
34 num[a[p]]+=val; 35 ans+=num[a[p]]*num[a[p]]; 36 } 37 38 int main() 39 { 40 ll n,m,i,j,k,x,y,z,l,r,sz; 41 while ( scanf("%lld%lld",&n,&m)!=EOF ) { 42 for ( i=1;i<=n;i++ ) scanf("%lld",&a[i]); 43 sz=sqrt(n); 44 for ( i=1;i<=m;i++ ) { 45 scanf("%lld%lld",&arr[i].l,&arr[i].r); 46 arr[i].id=i; 47 arr[i].belong=(arr[i].l-1)/sz+1; 48 } 49 sort(arr+1,arr+1+m,cmp1); 50 l=1; 51 r=0; 52 ans=0; 53 for ( i=1;i<=m;i++ ) { 54 for ( ;r<arr[i].r;r++ ) update(r+1,1); 55 for ( ;r>arr[i].r;r-- ) update(r,-1); 56 for ( ;l>arr[i].l;l-- ) update(l-1,1); 57 for ( ;l<arr[i].l;l++ ) update(l,-1); 58 if ( arr[i].l==arr[i].r ) { 59 arr[i].a=0; 60 arr[i].b=1; 61 continue; 62 } 63 arr[i].a=ans-(arr[i].r-arr[i].l+1); 64 arr[i].b=(ll)(arr[i].r-arr[i].l+1)*(arr[i].r-arr[i].l); 65 k=gcd(arr[i].a,arr[i].b); 66 arr[i].a/=k; 67 arr[i].b/=k; 68 } 69 sort(arr+1,arr+1+m,cmp2); 70 for ( i=1;i<=m;i++ ) printf("%lld/%lld\n",arr[i].a,arr[i].b); 71 72 } 73 return 0; 74 }
BZOJ2038

練習題:

1.(HDOJ4858)http://acm.hdu.edu.cn/showproblem.php?pid=4858

分析:圖的分塊。設點i的點權為val[i],與點i相鄰的項目的能量值之和為sum[i]。將圖中的點分為重點和輕點,重點是那些邊的度數超過sqrt(m)(該值可以自己規定)的點,除了重點剩下的點都是輕點。對於構圖,重點只和重點建邊,輕點可以和所有點建邊。每次更新,對於重點i和輕點來說來說都是更新自己的val[i]和相鄰點的sum[i]。而對於查詢操作來說,重點直接輸出sum[i],而輕點則采用暴力做法:遍歷其每一個相鄰點,答案累加上相鄰的val[i]。采用的思想是分攤復雜度的思想

技術分享圖片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<cmath>
 6 using namespace std;
 7 typedef long long ll;
 8 const ll maxn=1e5+100;
 9 struct edge{
10     ll u,v;
11 }arr[maxn];
12 ll val[maxn],du[maxn],sum[maxn];
13 bool ok[maxn];
14 vector<ll>G[maxn];
15 
16 int main()
17 {
18     ll T,i,j,k,x,y,z,ans,cnt,n,m,sz,u,v,op,q;
19     scanf("%lld",&T);
20     while ( T-- ) {
21         scanf("%lld%lld",&n,&m);
22         for ( i=1;i<=n;i++ ) {
23             G[i].clear(); 
24             ok[i]=false;
25             du[i]=val[i]=sum[i]=0;
26         }
27         for ( i=1;i<=m;i++ ) {
28             scanf("%lld%lld",&arr[i].u,&arr[i].v);
29             du[arr[i].u]++;
30             du[arr[i].v]++;
31         }
32         sz=sqrt(m);
33         for ( i=1;i<=n;i++ ) {
34             if ( du[i]>sz ) ok[i]=true;
35         }
36         for ( i=1;i<=m;i++ ) {
37             x=arr[i].u;
38             y=arr[i].v;
39             if ( ok[x] ) {
40                 if ( ok[y] ) {
41                     G[x].push_back(y);
42                     G[y].push_back(x);
43                 }
44                 else {
45                     G[y].push_back(x);
46                 }
47             }
48             else {
49                 if ( ok[y] ) {
50                     G[x].push_back(y);
51                 }
52                 else {
53                     G[x].push_back(y);
54                     G[y].push_back(x);
55                 }
56             }
57         }
58         scanf("%lld",&q);
59         while ( q-- ) {
60             scanf("%lld",&op);
61             if ( op==0 ) {
62                 scanf("%lld%lld",&u,&x);
63                 val[u]+=x;
64                 for ( i=0;i<G[u].size();i++ ) {
65                     v=G[u][i];
66                     sum[v]+=x;
67                 }
68             }
69             else {
70                 scanf("%lld",&u);
71                 if ( ok[u] ) printf("%lld\n",sum[u]);
72                 else {
73                     ans=0;
74                     for ( i=0;i<G[u].size();i++ ) {
75                         v=G[u][i];
76                         ans+=val[v];
77                     }
78                     printf("%lld\n",ans);
79                 }
80             }
81         }
82     }
83     return 0;
84 }
HDOJ4858

2.(HDOJ4467)http://acm.hdu.edu.cn/showproblem.php?pid=4467

題意:給你n個點(每個點都有一個顏色,0代表黑色,1代表白色),m條邊,每條邊有一個權值.現在有有兩個操作,一個是修改某個點的顏色(白變成黑/黑變成白),另外一個是詢問那些邊的兩個端點都為指定顏色的權值總和

分析:采用上題相同的思想。將所有點分為重點和輕點,但是這次重點和重點之前的邊要建在一個圖中,剩余的邊要建在另一個圖中。對於最後訪問的顏色,只有三種情況黑+黑(求和為0),黑+白(求和為1),白+白(求和為2),所以用a[0],a[1],a[2]分別對應的答案。對於重點i設置一個sum[i][2],sum[i][0]表示所有與他相鄰且顏色為0(黑)的點的邊權之和,sum[i][1]同理。更新時,對於重點i來說拿sum[i][0]和sum[i][1]去直接更新a數組,同時將其相鄰的重點的sum值進行修改。而對於輕點i來說,遍歷所有與i相連的邊,暴力更新a數組,而當其相鄰點為重點時則需要更新一下重點的sum數組。對於查詢操作,直接輸出a數組中的值即可

技術分享圖片
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<vector>
  5 #include<cmath>
  6 using namespace std;
  7 typedef long long ll;
  8 const ll maxn=1e5+10;
  9 ll sum[maxn][2],a[5],color[maxn],du[maxn];
 10 bool ok[maxn];
 11 struct Edge{
 12     ll x,y,val;
 13 }arr[maxn],arr_[maxn];
 14 struct edge{
 15     ll v,val;
 16     edge(ll _v=0,ll _val=0):v(_v),val(_val) {}
 17 };
 18 vector<edge>G[maxn],G_[maxn];
 19 
 20 bool cmp(Edge x,Edge y)
 21 {
 22     if ( x.x==y.x ) return x.y<y.y;
 23     return x.x<y.x;
 24 }
 25 
 26 int main()
 27 {
 28     ll n,m,i,j,k,x,y,z,sz,cnt,q,ans,h=0;
 29     char op[10];
 30     while ( scanf("%lld%lld",&n,&m)!=EOF ) {
 31         for ( i=1;i<=n;i++ ) {
 32             sum[i][0]=sum[i][1]=0;
 33             ok[i]=false;
 34             du[i]=0;
 35             G[i].clear();
 36             G_[i].clear();
 37         }
 38         memset(a,0,sizeof(a));
 39         for ( i=1;i<=n;i++ ) scanf("%lld",&color[i]);
 40         for ( i=1;i<=m;i++ ) {
 41             scanf("%lld%lld%lld",&x,&y,&arr[i].val);
 42             if ( x>y ) swap(x,y);
 43             arr[i].x=x;
 44             arr[i].y=y;
 45             a[color[x]+color[y]]+=arr[i].val;
 46         }
 47         sort(arr+1,arr+1+m,cmp);
 48         cnt=0;
 49         for ( i=1;i<=m;i=j ) {
 50             for ( j=i+1;j<=m;j++ ) {
 51                 if ( arr[i].x==arr[j].x && arr[i].y==arr[j].y ) {
 52                     arr[i].val+=arr[j].val;
 53                 }
 54                 else break;
 55             }
 56             arr_[++cnt]=arr[i];
 57         }
 58         sz=sqrt(cnt);
 59         for ( i=1;i<=cnt;i++ ) {
 60             du[arr_[i].x]++;
 61             du[arr_[i].y]++;
 62         }
 63         for ( i=1;i<=n;i++ ) {
 64             if ( du[i]>sz ) ok[i]=true;
 65         }
 66         for ( i=1;i<=cnt;i++ ) {
 67             x=arr_[i].x;
 68             y=arr_[i].y;
 69             if ( ok[x] ) {
 70                 if ( ok[y] ) {
 71                     G_[x].push_back(edge(y,arr_[i].val));
 72                     G_[y].push_back(edge(x,arr_[i].val));
 73                     sum[x][color[y]]+=arr_[i].val;
 74                     sum[y][color[x]]+=arr_[i].val;
 75                 }
 76                 else {
 77                     G[y].push_back(edge(x,arr_[i].val));
 78                     sum[x][color[y]]+=arr_[i].val;
 79                 }
 80             }
 81             else {
 82                 if ( ok[y] ) {
 83                     G[x].push_back(edge(y,arr_[i].val));
 84                     sum[y][color[x]]+=arr_[i].val;
 85                 }
 86                 else {
 87                     G[x].push_back(edge(y,arr_[i].val));
 88                     G[y].push_back(edge(x,arr_[i].val));
 89                 }
 90             }
 91         }
 92         printf("Case %lld:\n",++h);
 93         scanf("%lld",&q);
 94         while ( q-- ) {
 95             scanf("%s",op);
 96             if ( op[0]==A ) {
 97                 scanf("%lld%lld",&x,&y);
 98                 printf("%lld\n",a[x+y]);
 99             }
100             else {
101                 scanf("%lld",&x);
102                 if ( ok[x] ) {
103                     a[color[x]+0]-=sum[x][0];
104                     a[color[x]+1]-=sum[x][1];
105                     a[1-color[x]+0]+=sum[x][0];
106                     a[1-color[x]+1]+=sum[x][1];
107                     for ( i=0;i<G_[x].size();i++ ) {
108                         y=G_[x][i].v;
109                         z=G_[x][i].val;
110                         sum[y][color[x]]-=z;
111                         sum[y][1-color[x]]+=z;
112                     }
113                 }
114                 else {
115                     for ( i=0;i<G[x].size();i++ ) {
116                         y=G[x][i].v;
117                         z=G[x][i].val;
118                         a[color[x]+color[y]]-=z;
119                         a[1-color[x]+color[y]]+=z;
120                         if ( ok[y] ) {
121                             sum[y][color[x]]-=z;
122                             sum[y][1-color[x]]+=z;
123                         }
124                     }
125                 }
126                 color[x]=1-color[x];
127             }
128         }
129     }
130     return 0;
131 }
HDOJ4467

專題訓練之莫隊算法