推荐博客/专栏: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
原文地址:https://www.cnblogs.com/HDUjackyan/p/8996172.html