莫队/分块 题目泛做
题目1 BZOJ2453 / 2120
算法讨论:
用pre[i]表示与第i个位置颜色相同的上个位置在哪里,那么对于l...r内,如果一个位置的pre[i] < l,则说明这个颜色是第一次出现。
然后暴力分块。因为修改的次数很少,所以每次修改就重新计算pre[i],对于涉及的块重新构块。然后对于整块的查询,直接在排好序的pre上二分就可以了。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int M = 1000000 + 5; 6 const int N = 10000 + 5; 7 const int K = 110; 8 9 inline int read() { 10 int x = 0; 11 char c = getchar(); 12 13 while(!isdigit(c)) c = getchar(); 14 while(isdigit(c)) { 15 x = x * 10 + c - '0'; 16 c = getchar(); 17 } 18 return x; 19 } 20 21 char ss[5]; 22 int n, m, size, tk; 23 int ckn[N], b[N], pre[N], last[M], a[N]; 24 int l[K], r[K]; 25 26 void prepare() { 27 size = (int) sqrt(n); 28 for(int i = 1; i <= n; ++ i) ckn[i] = (i - 1) / size + 1; 29 tk = n / size + 1 - (n % size == 0); 30 for(int i = 1; i <= tk; ++ i) { 31 l[i] = (i - 1) * size + 1; 32 r[i] = min(i * size, n); 33 for(int j = l[i]; j <= r[i]; ++ j) { 34 b[j] = pre[j]; 35 } 36 sort(b + l[i], b + r[i] + 1); 37 } 38 } 39 40 void reset(int num) { 41 for(int i = l[num]; i <= r[num]; ++ i) { 42 b[i] = pre[i]; 43 } 44 sort(b + l[num], b + r[num] + 1); 45 } 46 47 void update(int x, int v) { 48 int tp; 49 50 for(int i = 1; i <= n; ++ i) last[a[i]] = 0; 51 a[x] = v; 52 for(int i = 1; i <= n; ++ i) { 53 tp = pre[i]; 54 pre[i] = last[a[i]]; 55 if(tp != pre[i]) reset(ckn[i]); 56 last[a[i]] = i; 57 } 58 } 59 60 int bs(int L, int R, int V) { 61 int mid, res, Down = L; 62 63 if(b[R] < V) return R - L + 1; 64 if(b[L] >= V) return 0; 65 while(L <= R) { 66 mid = L + (R - L) / 2; 67 if(b[mid] < V) { 68 L = mid + 1; 69 res = mid; 70 } 71 else 72 R = mid - 1; 73 } 74 return res - Down + 1; 75 } 76 77 void query(int L, int R) { 78 int n1 = ckn[L], n2 = ckn[R]; 79 int res = 0; 80 81 if(n1 == n2) { 82 for(int i = L; i <= R; ++ i) { 83 if(pre[i] < L) ++ res; 84 } 85 printf("%d\n", res); 86 } 87 else { 88 for(int i = L; i <= r[n1]; ++ i) 89 if(pre[i] < L) ++ res; 90 for(int i = l[n2]; i <= R; ++ i) 91 if(pre[i] < L) ++ res; 92 for(int i = n1 + 1; i < n2; ++ i) 93 res += bs(l[i], r[i], L); 94 printf("%d\n", res); 95 } 96 } 97 98 int main() { 99 int x, y; 100 101 n = read(); m = read(); 102 for(int i = 1; i <= n; ++ i) a[i] = read(); 103 for(int i = 1; i <= n; ++ i) { 104 pre[i] = last[a[i]]; 105 last[a[i]] = i; 106 } 107 prepare(); 108 for(int i = 1; i <= m; ++ i) { 109 scanf("%s", ss); 110 x = read(); y = read(); 111 if(ss[0] == 'Q') { 112 query(x, y); 113 } 114 else { 115 update(x, y); 116 } 117 } 118 return 0; 119 }
题目2 BZOJ3052 WC2013 糖果公园
算法讨论:
带修改的树上莫队。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <cctype> 7 #include <cmath> 8 #include <stack> 9 10 using namespace std; 11 12 const int N = 100000 + 5; 13 typedef long long ll; 14 15 inline int read() { 16 int x = 0; 17 char c = getchar(); 18 19 while(!isdigit(c)) c = getchar(); 20 while(isdigit(c)) { 21 x = x * 10 + c - '0'; 22 c = getchar(); 23 } 24 return x; 25 } 26 27 int buf[30]; 28 29 inline void output(ll x) { 30 int p = 0; 31 32 buf[0] = 0; 33 if(x == 0) p ++; 34 else { 35 while(x) { 36 buf[p ++] = x % 10; 37 x /= 10; 38 } 39 } 40 for(int j = p - 1; j >= 0; -- j) 41 putchar('0' + buf[j]); 42 } 43 44 ll ans[N], tot = 0; 45 int n, m, q, size, cnt, tk, tim; 46 int head[N], fa[N], f[N][18], seq[N], v[N], w[N]; 47 int ckn[N], depth[N], son[N], pre[N], c[N]; 48 bool flag[N]; int vis[N]; 49 stack <int> s; 50 51 struct Edge { 52 int from, to, next; 53 }edges[N << 1]; 54 struct Query { 55 int x, v, pre; 56 }C[N]; 57 struct query { 58 int id, u, v, t; 59 bool operator < (const query &k) const { 60 if(ckn[u] == ckn[k.u] && ckn[v] == ckn[k.v]) return t < k.t; 61 else if(ckn[u] == ckn[k.u]) return ckn[v] < ckn[k.v]; 62 else return ckn[u] < ckn[k.u]; 63 } 64 }Q[N]; 65 66 void insert(int from, int to) { 67 ++ cnt; 68 edges[cnt].from = from; edges[cnt].to = to; 69 edges[cnt].next = head[from]; head[from] = cnt; 70 } 71 72 void dfs(int u, int f) { 73 fa[u] = f; seq[u] = ++ tim; 74 for(int i = head[u]; i; i = edges[i].next) { 75 int v = edges[i].to; 76 77 if(v != f) { 78 depth[v] = depth[u] + 1; 79 dfs(v, u); 80 son[u] += son[v]; 81 if(son[u] >= size) { 82 ++ tk; 83 son[u] = 0; 84 while(!s.empty()) { 85 int cur = s.top(); s.pop(); 86 ckn[cur] = tk; 87 } 88 } 89 } 90 } 91 s.push(u); son[u] ++; 92 } 93 94 void prepare() { 95 memset(f, -1, sizeof f); 96 for(int i = 1; i <= n; ++ i) f[i][0] = fa[i]; 97 for(int j = 1; (1 << j) <= n; ++ j) { 98 for(int i = 1; i <= n; ++ i) { 99 if(f[i][j - 1] != -1) { 100 f[i][j] = f[f[i][j - 1]][j - 1]; 101 } 102 } 103 } 104 } 105 106 int lca(int a, int b) { 107 int i; 108 109 if(depth[a] < depth[b]) swap(a, b); 110 for(i = 0; (1 << i) <= depth[a]; ++ i); 111 -- i; 112 for(int j = i; j >= 0; -- j) { 113 if(depth[a] - depth[b] >= (1 << j)) 114 a = f[a][j]; 115 } 116 if(a == b) return a; 117 for(int j = i; j >= 0; -- j) { 118 if(f[a][j] != -1 && f[a][j] != f[b][j]) { 119 a = f[a][j]; 120 b = f[b][j]; 121 } 122 } 123 return f[a][0]; 124 } 125 126 void rever(int u) { 127 if(flag[u]) { 128 flag[u] = false; 129 tot -= 1LL * w[vis[c[u]]] * v[c[u]]; 130 vis[c[u]] --; 131 } 132 else { 133 flag[u] = true; 134 vis[c[u]] ++; 135 tot += 1LL * w[vis[c[u]]] * v[c[u]]; 136 } 137 } 138 139 void Getpath(int u, int fi) { 140 while(u != fi) { 141 rever(u); 142 u = fa[u]; 143 } 144 } 145 146 void change(int x, int v) { 147 if(flag[x]) { 148 rever(x); c[x] = v; rever(x); 149 } 150 else c[x] = v; 151 } 152 153 void solve(int nl, int nr, int &zl, int &zr, int ts) { 154 int Lca; 155 156 Lca = lca(nl, zl); 157 Getpath(nl, Lca); Getpath(zl, Lca); 158 Lca = lca(nr, zr); 159 Getpath(nr, Lca); Getpath(zr, Lca); 160 Lca = lca(nl, nr); 161 rever(Lca); ans[Q[ts].id] = tot; rever(Lca); 162 zl = nl; zr = nr; 163 } 164 165 #define ONLINE_JUDGE 166 167 int main() { 168 //int __size__ = 64 <<20; //这里谁<<20位,就是多少M的栈 169 //char*__p__ =(char*)malloc(__size__)+ __size__; 170 //__asm__("movl %0, %%esp\n"::"r"(__p__)); 171 172 #ifndef ONLINE_JUDGE 173 freopen("park.in", "r", stdin); 174 freopen("park.out", "w", stdout); 175 #endif 176 177 int x, y; 178 179 n = read(); m = read(); q = read(); 180 for(int i = 1; i <= m; ++ i) v[i] = read(); 181 for(int i = 1; i <= n; ++ i) w[i] = read(); 182 for(int i = 1; i < n; ++ i) { 183 x = read(); y = read(); 184 insert(x, y); insert(y, x); 185 } 186 for(int i = 1; i <= n; ++ i) pre[i] = c[i] = read(); 187 depth[1] = 1; //size = (int) pow((double) n, (double) 2 / 3); 188 size = 1500; 189 dfs(1, -1); 190 if(!s.empty()) { 191 ++ tk; 192 while(!s.empty()) { 193 int cur = s.top(); s.pop(); 194 ckn[cur] = tk; 195 } 196 } 197 prepare(); 198 199 int type, t1 = 0, t2 = 0; 200 201 for(int i = 1; i <= q; ++ i) { 202 type = read(); 203 if(!type) { 204 ++ t1; 205 C[t1].x = read(); C[t1].v = read(); C[t1].pre = pre[C[t1].x]; 206 pre[C[t1].x] = C[t1].v; 207 } 208 else { 209 ++ t2; 210 Q[t2].u = read(); Q[t2].v = read(); Q[t2].id = t2; Q[t2].t = t1; 211 if(seq[Q[t2].u] > seq[Q[t2].v]) swap(Q[t2].u, Q[t2].v); 212 } 213 } 214 215 int L = 1, R = 1; 216 217 sort(Q + 1, Q + t2 + 1); 218 for(int i = 1; i <= Q[1].t; ++ i) { 219 change(C[i].x, C[i].v); 220 } 221 solve(Q[1].u, Q[1].v, L, R, 1); 222 for(int i = 2; i <= t2; ++ i) { 223 for(int t = Q[i - 1].t + 1; t <= Q[i].t; ++ t) 224 change(C[t].x, C[t].v); 225 for(int t = Q[i - 1].t; t > Q[i].t; -- t) 226 change(C[t].x, C[t].pre); 227 solve(Q[i].u, Q[i].v, L, R, i); 228 } 229 for(int i = 1; i <= t2; ++ i) { 230 output(ans[i]); 231 puts(""); 232 } 233 234 #ifndef ONLINE_JUDGE 235 fclose(stdin); fclose(stdout); 236 #endif 237 return 0; 238 }
题目3 NOI2003 文本编辑器
算法讨论:
块状链表。支持插入、删除、找到第x个数的位置等操作。
对于插入操作,
如果要插入的当前块的大小已经满块
那么就新建立一个块,插到原来的两块之间,修改块之间的指针
然后把这个新块之前的块的光标之后的东西复制到新块,然后更新原块的size
然后比较这两个块的大小,把字符插入到较小的那个块中去。
对于删除操作
首先判断当前块的光标之后的元素个数是否比删除的东西多,如果多的话,就直接在块内删除
如果不是,则直接把块改了。
1 #include <cstdlib> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <cstdio> 6 7 using namespace std; 8 9 const int K = 3000 + 5; 10 11 char opt[10]; 12 int m; 13 int cur_mouse, cur_blo, tk, size; 14 //cur_mouse 记录光标在某个块内的位置 15 //cur_blo记录当前在某个块 tk是块的总数 size是块的上限大小 16 struct Node { 17 char s[K]; 18 int sz, pre, next; 19 }blo[K]; 20 21 void Move() { 22 int mouse; 23 scanf("%d", &mouse); 24 cur_blo = blo[0].next; 25 while(mouse > blo[cur_blo].sz) { 26 mouse -= blo[cur_blo].sz; cur_blo = blo[cur_blo].next; 27 } 28 cur_mouse = mouse; 29 } 30 31 void Insert() { 32 int cmd, imouse = cur_mouse, iblo = cur_blo; 33 char c; 34 scanf("%d", &cmd); 35 c = getchar(); 36 while(cmd --) { 37 while(c < 32 || c > 126) c = getchar(); 38 if(blo[iblo].sz == size) { 39 ++ tk; 40 blo[tk].next = blo[iblo].next; 41 blo[tk].pre = iblo; blo[tk].sz = size - imouse; 42 blo[blo[iblo].next].pre = tk; 43 blo[iblo].next = tk; 44 for(int i = 1; i <= blo[tk].sz; ++ i) 45 blo[tk].s[i] = blo[iblo].s[imouse + i]; 46 blo[iblo].sz = imouse; 47 if(blo[tk].sz < blo[iblo].sz) { 48 imouse = 0; iblo = tk; 49 } 50 } 51 blo[iblo].sz ++; 52 for(int i = blo[iblo].sz; i > imouse; -- i) { 53 blo[iblo].s[i] = blo[iblo].s[i - 1]; 54 } 55 blo[iblo].s[++ imouse] = c; 56 c = getchar(); 57 } 58 } 59 60 void Delete() { 61 int cmd, imouse = cur_mouse, iblo = cur_blo; 62 scanf("%d", &cmd); 63 while(cmd) { 64 int left = blo[iblo].sz - imouse; 65 if(cmd > left) { 66 cmd -= left; blo[iblo].sz = imouse; 67 iblo = blo[iblo].next; 68 imouse = 0; 69 } 70 else { 71 for(int i = imouse + cmd + 1; i <= blo[iblo].sz; ++ i) 72 blo[iblo].s[i - cmd] = blo[iblo].s[i]; 73 blo[iblo].sz -= cmd; 74 cmd = 0; 75 } 76 } 77 } 78 79 void Next() { 80 if(cur_mouse != blo[cur_blo].sz) cur_mouse ++; 81 else { 82 cur_blo = blo[cur_blo].next; 83 while(blo[cur_blo].sz == 0) { 84 blo[blo[cur_blo].pre].next = blo[cur_blo].next; 85 blo[blo[cur_blo].next].pre = blo[cur_blo].pre; 86 cur_blo = blo[cur_blo].next; 87 } 88 cur_mouse = 1; 89 } 90 } 91 92 void Prev() { 93 if(cur_mouse) cur_mouse --; 94 else { 95 cur_blo = blo[cur_blo].pre; 96 while(blo[cur_blo].sz == 0) { 97 blo[blo[cur_blo].pre].next = blo[cur_blo].next; 98 blo[blo[cur_blo].next].pre = blo[cur_blo].pre; 99 cur_blo = blo[cur_blo].pre; 100 } 101 cur_mouse = blo[cur_blo].sz - 1; 102 } 103 } 104 105 void Get() { 106 int cmd, imouse = cur_mouse, iblo = cur_blo; 107 scanf("%d", &cmd); 108 while(cmd) { 109 if(blo[iblo].sz == 0) { 110 blo[blo[iblo].next].pre = blo[iblo].pre; 111 blo[blo[iblo].pre].next = blo[iblo].next; 112 iblo = blo[iblo].next; 113 } 114 int left = blo[iblo].sz - imouse; 115 if(cmd > left) { 116 for(int i = imouse + 1; i <= blo[iblo].sz; ++ i) 117 putchar(blo[iblo].s[i]); 118 cmd -= left; 119 imouse = 0; 120 iblo = blo[iblo].next; 121 } 122 else { 123 for(int i = imouse + 1; i <= imouse + cmd; ++ i) 124 putchar(blo[iblo].s[i]); 125 cmd = 0; 126 } 127 } 128 puts(""); 129 } 130 131 #define ONLINE_JUDGE 132 133 int main() { 134 #ifndef ONLINE_JUDGE 135 freopen("editor2003.in", "r", stdin); 136 freopen("editor2003.out", "w", stdout); 137 #endif 138 139 scanf("%d", &m); 140 size = 2000; 141 tk = 1; cur_blo = 1; 142 blo[0].next = 1;//忘记链表初始化。。额。 143 while(m --) { 144 scanf("%s", opt); 145 if(opt[0] == 'M') Move(); 146 else if(opt[0] == 'I') Insert(); 147 else if(opt[0] == 'D') Delete(); 148 else if(opt[0] == 'G') Get(); 149 else if(opt[0] == 'P') Prev(); 150 else if(opt[0] == 'N') Next(); 151 } 152 153 #ifndef ONLINE_JUDGE 154 fclose(stdin); fclose(stdout); 155 #endif 156 157 return 0; 158 }