标签:
分块算法主要用于给定序列的区间询问问题,能够以较小的时间代价暴力求解,时间复杂度一般在O(n*n^0.5)。关键在O(1) 维护好某一区间在增加或者减少一个边界元素所带来的影响。需要注意的就是在更新的区间的时候要先放大在缩小,否则可能出现当前区间左右边界互换的情况,这 个影响某一些题可能没有影响,但是极有可能出错。
时间复杂度:先考虑左边界的时间复杂度,由于分成了sqrt(n)块,而同一块中左标移动的范围最多是sqrt(n),那相邻块跳 转的情况呢?可以虚拟出每块中有至少一个询问进行思考,那么相邻块之间的移动次数最大为2*sqrt(n)。由于共有Q次询问,因此最终时间复杂度为 O(Q*sqrt(n))。再考虑右边界,对于同一块内的右边界来说,其值是单调递增的,因此时间复杂度为O(n),相邻块跳转为O(2*n),由于共有 sqrt(n)块,因此最终时间复杂度为O(n*sqrt(n))。
---以上参考自 http://www.cnblogs.com/Lyush/archive/2013/08/16/3263247.html
1. Codefoces 86D Powerful array
题意: 给定n个数的一个序列, 再给出t组查询 (n, t <= 200000)问区间[l, r]里每个数的出现次数的平方乘上这个数的和是多少。
分析:分块的模板题,将询问离线处理,令sum[x]表示x在区间内出现的次数。扫描到ai时,若是进入区间则ans+=(2*sum[ai]+1)*ai, sum[ai]++,若是出区间则sum[ai]--,ans-=(2*sum[ai]+1)*ai。暴力维护区间即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 #include<set> 9 #include<string> 10 typedef long long LL; 11 using namespace std; 12 #define pii pair<int,int> 13 const int inf = 0x3f3f3f3f; 14 const int N = 200010; 15 16 struct Node{ 17 int id; 18 int L, R, bel; 19 Node(int id=0, int L=0, int R=0, int bel=0) : id(id),L(L),R(R),bel(bel){} 20 bool operator < (const Node &cmp) const { 21 if(bel != cmp.bel) return bel < cmp.bel; 22 return R < cmp.R; 23 } 24 } node[N]; 25 LL a[N]; 26 LL ans[N]; 27 int cnt[1000100]; 28 int L, R; 29 LL ret; 30 31 LL query(int l, int r) 32 { 33 for(int i=l; i<L; i++) { 34 ret += (cnt[a[i]]<<1|1)*a[i]; 35 cnt[a[i]]++; 36 } 37 for(int i=R+1; i<=r; i++) { 38 ret += (cnt[a[i]]<<1|1)*a[i]; 39 cnt[a[i]]++; 40 } 41 for(int i=L; i<l; i++) { 42 cnt[a[i]]--; 43 ret -= (cnt[a[i]]<<1|1)*a[i]; 44 } 45 46 for(int i=r+1; i<=R; i++) { 47 cnt[a[i]]--; 48 ret -= (cnt[a[i]]<<1|1)*a[i]; 49 } 50 L = l, R = r; 51 return ret; 52 } 53 54 int main() 55 { 56 int i,j,k,m,n, x, y; 57 while(scanf("%d %d",&n,&m) == 2) 58 { 59 int block = sqrt(n*1.0); 60 for(i=1; i<=n; i++) scanf("%I64d",a+i); 61 for(i=1; i<=m; i++) { 62 scanf("%d %d",&x,&y); 63 node[i] = Node(i, x, y, x/block); 64 } 65 sort(node+1, node+1+m); 66 memset(cnt, 0, sizeof(cnt)); 67 L = R = ret = 0; 68 for(i=1; i<=m; i++) { 69 ans[node[i].id] = query(node[i].L, node[i].R); 70 } 71 for(i=1; i<=m; i++) printf("%I64d\n", ans[i]); 72 } 73 return 0; 74 }
题意:给定一个序列,序列由1-N个元素全排列而成,求任意区间连续的段数。例如序列2,3,5,6,9就是三段(2, 3) (5, 6)(9)。
分析:也是离线处理,分块排好序,O(1)的维护就是每新添加一个元素 t 查看 t-1 与 t+1 是否都在区间内,如是则段数-1,如果都不在,则段数+1。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 #include<set> 9 #include<string> 10 typedef long long LL; 11 using namespace std; 12 #define pii pair<int,int> 13 const int inf = 0x3f3f3f3f; 14 const int N = 100010; 15 16 struct Node{ 17 int id; 18 int L, R, bel; 19 Node(int id=0, int L=0, int R=0, int bel=0) : id(id),L(L),R(R),bel(bel){} 20 bool operator < (const Node &cmp) const { 21 if(bel != cmp.bel) return bel < cmp.bel; 22 return R < cmp.R; 23 } 24 } node[N]; 25 int a[N]; 26 int ans[N]; 27 int vis[N]; 28 int L, R; 29 int ret; 30 31 int query(int l, int r, int k) 32 { 33 if(k == 1) { 34 ret = 0; 35 for(int i=l; i<=r; i++) { 36 if(vis[a[i]-1] && vis[a[i]+1]) 37 ret--; 38 else if(!vis[a[i]-1] && !vis[a[i]+1]) 39 ret++; 40 vis[a[i]] = 1; 41 } 42 L = l, R = r; 43 return ret; 44 } 45 for(int i=l; i<L; i++) { 46 if(vis[a[i]-1] && vis[a[i]+1]) 47 ret--; 48 else if(!vis[a[i]-1] && !vis[a[i]+1]) 49 ret++; 50 vis[a[i]] = 1; 51 } 52 for(int i=R+1; i<=r; i++) { 53 if(vis[a[i]-1] && vis[a[i]+1]) 54 ret--; 55 else if(!vis[a[i]-1] && !vis[a[i]+1]) 56 ret++; 57 vis[a[i]] = 1; 58 } 59 for(int i=L; i<l; i++) { 60 if(vis[a[i]-1] && vis[a[i]+1]) 61 ret++; 62 else if(!vis[a[i]-1] && !vis[a[i]+1]) 63 ret--; 64 vis[a[i]] = 0; 65 } 66 for(int i=r+1; i<=R; i++) { 67 if(vis[a[i]-1] && vis[a[i]+1]) 68 ret++; 69 else if(!vis[a[i]-1] && !vis[a[i]+1]) 70 ret--; 71 vis[a[i]] = 0; 72 } 73 L = l, R = r; 74 return ret; 75 } 76 77 int main() 78 { 79 int i,j,k,m,n, x, y; 80 int t; 81 scanf("%d",&t); 82 while(t--) 83 { 84 scanf("%d%d",&n,&m); 85 int block = sqrt(n*1.0); 86 for(i=1; i<=n; i++) scanf("%d",a+i); 87 for(i=1; i<=m; i++) { 88 scanf("%d %d",&x,&y); 89 node[i] = Node(i, x, y, x/block); 90 } 91 sort(node+1, node+1+m); 92 memset(vis, 0, sizeof(vis)); 93 for(i=1; i<=m; i++) { 94 ans[node[i].id] = query(node[i].L, node[i].R, i); 95 } 96 for(i=1; i<=m; i++) printf("%d\n", ans[i]); 97 } 98 return 0; 99 }
标签:
原文地址:http://www.cnblogs.com/WCB-ACM/p/4951372.html