1.分块
大概就是把序列分成若干块,预处理出一些东西,整块打标记,边角暴力。
当然不一定是对着序列分块。可能对着任何东西分块,比如哈希冲突...
复杂度随着题目相应变化,一般用均值不等式来确定块的大小。
例题首先是hzwer的分块9题。
说两个神奇的分块思想。
1.当暴力复杂度是n²m,且每个元素贡献独立的时候,可以把这些元素分成n0.5块,分别暴力。
总复杂度是n1.5m(有用吗...)
2.对时间/操作分块。
把操作分成若干块,块大小是T。之后对于每一块,预处理之前的影响,暴力查块内的影响。
总复杂度是O(预处理复杂度 * T + m² / T * 暴力查询复杂度)
2.莫队
先%%%莫涛。
两个指针跳来跳去......
普通莫队:就是离线,把询问排序,使得挪动指针的总次数不大于n1.5。
例题:小Z的袜子 小B的询问 大爷的字符串 小清新人渣的本愿
带修莫队:三个维度排序。时间作为第三关键字。
相当于三个指针跳来跳去,第三个指针在时间上。这样就懂了吧。
树上莫队:用括号序列转成序列莫队。
先讲一下括号序列,DFS序,欧拉序的区别。
- DFS序就是DFS时,第一次进入点时将其加入序列,长度为n。树剖就是用的一种DFS序。
- 括号序列:出来的时候额外加入一次,长度为2n。
- 欧拉序:每次切换节点时,将当前节点加入序列。长度为2n - 1,因为每个非根节点都会自己加入一次,让父亲加入一次。
把括号序列搞出来。我们统计其中出现一次的点。
对于路径x - y的询问,先让first[x] < first[y]
求lca:z。如果z == x,那么直接用first[x] - first[y]
否则就用last[x] - first[y],然后查询时加上z。
此处的first和last表示第一,二次在序列中出现的位置。
例题:SP10707 Count on a tree II
1 #include <cstdio> 2 #include <algorithm> 3 #include <cmath> 4 5 const int N = 200010; 6 7 struct Edge { 8 int nex, v; 9 }edge[N << 1]; int top; 10 11 int fr[N], e[N], a[N], first[N], last[N], num, val[N], X[N], fa[N][20], pw[N], d[N], n, ans, bin[N]; 12 bool vis[N]; 13 14 struct ASK { 15 int l, r, t, ans, ex; 16 inline bool operator <(const ASK &w) const { 17 if(fr[l] != fr[w.l]) { 18 return l < w.l; 19 } 20 return r < w.r; 21 } 22 }ask[N]; 23 24 inline bool cmp(const ASK &A, const ASK &B) { 25 return A.t < B.t; 26 } 27 28 inline void add(int x, int y) { 29 top++; 30 edge[top].v = y; 31 edge[top].nex = e[x]; 32 e[x] = top; 33 return; 34 } 35 36 void DFS(int x, int f) { 37 a[++num] = x; 38 first[x] = num; 39 fa[x][0] = f; 40 d[x] = d[f] + 1; 41 for(int i = e[x]; i; i = edge[i].nex) { 42 int y = edge[i].v; 43 if(y == f) { 44 continue; 45 } 46 DFS(y, x); 47 } 48 a[++num] = x; 49 last[x] = num; 50 return; 51 } 52 53 inline int lca(int x, int y) { 54 if(d[x] > d[y]) { 55 std::swap(x, y); 56 } 57 int t = pw[n]; 58 while(t >= 0 && d[x] != d[y]) { 59 if(d[fa[y][t]] >= d[x]) { 60 y = fa[y][t]; 61 } 62 t--; 63 } 64 if(x == y) { 65 return x; 66 } 67 t = pw[n]; 68 while(t >= 0 && fa[x][0] != fa[y][0]) { 69 if(fa[x][t] != fa[y][t]) { 70 x = fa[x][t]; 71 y = fa[y][t]; 72 } 73 t--; 74 } 75 return fa[x][0]; 76 } 77 78 inline void add(int x) { 79 if(!bin[val[x]]) { 80 ans++; 81 } 82 bin[val[x]]++; 83 return; 84 } 85 86 inline void del(int x) { 87 bin[val[x]]--; 88 if(!bin[val[x]]) { 89 ans--; 90 } 91 return; 92 } 93 94 inline void work(int p) { 95 int x = a[p]; 96 if(vis[x]) { 97 del(x); 98 } 99 else { 100 add(x); 101 } 102 vis[x] ^= 1; 103 return; 104 } 105 106 int main() { 107 int m; 108 scanf("%d%d", &n, &m); 109 for(int i = 2; i <= n; i++) { 110 pw[i] = pw[i >> 1] + 1; 111 } 112 int T = sqrt(n << 1); 113 for(int i = 1; i <= n; i++) { 114 scanf("%d", &val[i]); 115 X[i] = val[i]; 116 } 117 std::sort(X + 1, X + n + 1); 118 int temp = std::unique(X + 1, X + n + 1) - X - 1; 119 for(int i = 1; i <= n; i++) { 120 val[i] = std::lower_bound(X + 1, X + temp + 1, val[i]) - X; 121 } 122 for(int i = 1, x, y; i < n; i++) { 123 scanf("%d%d", &x, &y); 124 add(x, y); 125 add(y, x); 126 } 127 DFS(1, 0); 128 for(int j = 1; j <= pw[n]; j++) { 129 for(int i = 1; i <= n; i++) { 130 fa[i][j] = fa[fa[i][j - 1]][j - 1]; 131 } 132 } 133 for(int i = 1; i <= n * 2; i++) { 134 fr[i] = (i - 1) / T + 1; 135 } 136 for(int i = 1, x, y; i <= m; i++) { 137 scanf("%d%d", &x, &y); 138 if(first[x] > first[y]) { 139 std::swap(x, y); 140 } 141 int z = lca(x, y); 142 if(z == x) { 143 ask[i].l = first[x]; 144 ask[i].r = first[y]; 145 } 146 else { 147 ask[i].l = last[x]; 148 ask[i].r = first[y]; 149 ask[i].ex = z; 150 } 151 ask[i].t = i; 152 } 153 154 std::sort(ask + 1, ask + m + 1); 155 int l = 1, r = 1; 156 work(1); 157 158 for(int i = 1; i <= m; i++) { 159 while(l > ask[i].l) { 160 l--; 161 work(l); 162 } 163 while(r < ask[i].r) { 164 r++; 165 work(r); 166 } 167 while(l < ask[i].l) { 168 work(l); 169 l++; 170 } 171 while(r > ask[i].r) { 172 work(r); 173 r--; 174 } 175 if(ask[i].ex) { 176 add(ask[i].ex); 177 } 178 ask[i].ans = ans; 179 if(ask[i].ex) { 180 del(ask[i].ex); 181 } 182 } 183 184 std::sort(ask + 1, ask + m + 1, cmp); 185 for(int i = 1; i <= m; i++) { 186 printf("%d\n", ask[i].ans); 187 } 188 return 0; 189 }