根号算法

分块与莫队

1.分块

大概就是把序列分成若干块,预处理出一些东西,整块打标记,边角暴力。

当然不一定是对着序列分块。可能对着任何东西分块,比如哈希冲突...

复杂度随着题目相应变化,一般用均值不等式来确定块的大小。

例题首先是hzwer的分块9题

说两个神奇的分块思想。

1.当暴力复杂度是n²m,且每个元素贡献独立的时候,可以把这些元素分成n0.5块,分别暴力。

总复杂度是n1.5m(有用吗...)

2.对时间/操作分块。

把操作分成若干块,块大小是T。之后对于每一块,预处理之前的影响,暴力查块内的影响。

总复杂度是O(预处理复杂度 * T + m² / T * 暴力查询复杂度)

2.莫队

先%%%莫涛。

两个指针跳来跳去......

普通莫队:就是离线,把询问排序,使得挪动指针的总次数不大于n1.5

例题:小Z的袜子 小B的询问  大爷的字符串  小清新人渣的本愿 

带修莫队:三个维度排序。时间作为第三关键字。

相当于三个指针跳来跳去,第三个指针在时间上。这样就懂了吧。

例题:洛谷P1903 [国家集训队]数颜色 / 维护队列

树上莫队:用括号序列转成序列莫队。

先讲一下括号序列,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 }
AC代码

可以发现上树之后代码量大了很多.....

树上带修莫队:前面两种嵌套一下就行了。

经典例题是糖果公园,码量有点大,不过主要是卡常。事实证明O2好用的一批......

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cmath>
  4 
  5 typedef long long LL;
  6 const int N = 400010;
  7 
  8 template<class T> inline void read(T &x) {
  9     x = 0;
 10     char c = getchar();
 11     while(c < '0' || c > '9') {
 12         c = getchar();
 13     }
 14     while(c >= '0' && c <= '9') {
 15         x = (x << 3) + (x << 1) + c - 48;
 16         c = getchar();
 17     }
 18     return;
 19 }
 20 
 21 struct Edge {
 22     int nex, v;
 23 }edge[N << 1]; int top;
 24 
 25 int fr[N], e[N], a[N], bin[N], first[N], last[N], num, fa[N][20], d[N], n, col[N], pw[N];
 26 LL ans, W[N], val[N];
 27 bool vis[N];
 28 
 29 struct ASK {
 30     int l, r, t, ex;
 31     LL ans;
 32     inline bool operator <(const ASK &w) const {
 33         if(fr[l] != fr[w.l]) {
 34             return l < w.l;
 35         }
 36         if(r != w.r) {
 37             return r < w.r;
 38         }
 39         return t < w.t;
 40     }
 41 }ask[N]; int topa;
 42 
 43 struct Change {
 44     int p, t, x, last;
 45 }change[N]; int topc;
 46 
 47 inline bool cmp(const ASK &A, const ASK &B) {
 48     return A.t < B.t;
 49 }
 50 
 51 inline void add(int x, int y) {
 52     top++;
 53     edge[top].v = y;
 54     edge[top].nex = e[x];
 55     e[x] = top;
 56     return;
 57 }
 58 
 59 void DFS(int x, int f) {
 60     a[++num] = x;
 61     first[x] = num;
 62     fa[x][0] = f;
 63     d[x] = d[f] + 1;
 64     for(int i = e[x]; i; i = edge[i].nex) {
 65         int y = edge[i].v;
 66         if(y == f) {
 67             continue;
 68         }
 69         DFS(y, x);
 70     }
 71     a[++num] = x;
 72     last[x] = num;
 73     return;
 74 }
 75 
 76 inline int lca(int x, int y) {
 77     if(d[x] > d[y]) {
 78         std::swap(x, y);
 79     }
 80     int t = pw[n];
 81     while(t >= 0 && d[y] > d[x]) {
 82         if(d[fa[y][t]] >= d[x]) {
 83             y = fa[y][t];
 84         }
 85         t--;
 86     }
 87     if(x == y) {
 88         return x;
 89     }
 90     t = pw[n];
 91     while(t >= 0 && fa[x][0] != fa[y][0]) {
 92         if(fa[x][t] != fa[y][t]) {
 93             x = fa[x][t];
 94             y = fa[y][t];
 95         }
 96         t--;
 97     }
 98     return fa[x][0];
 99 }
100 
101 inline void add(int x) {
102     //bin[col[x]]++;
103     (*(bin + (*(col + x))))++;
104     //ans += W[bin[col[x]]] * val[col[x]];
105     ans += (*(W + (*(bin + (*(col + x)))))) * (*(val + (*(col + x))));
106     return;
107 }
108 
109 inline void del(int x) {
110     //ans -= W[bin[col[x]]] * val[col[x]];
111     ans -= (*(W + (*(bin + (*(col + x)))))) * (*(val + (*(col + x))));
112     //bin[col[x]]--;
113     (*(bin + (*(col + x))))--;
114     return;
115 }
116 
117 inline void work(int p) {
118     int x = *(a + p);
119     (*(vis + x)) ? del(x) : add(x);
120     vis[x] ^= 1;
121     return;
122 }
123 
124 int main() {
125     int m, q;
126     read(n);
127     read(m);
128     read(q);
129     int T = pow(n << 1, 2.0 / 3.0);
130     for(int i = 1; i <= m; i++) {
131         read(val[i]);
132     }
133     for(int i = 1; i <= n; i++) {
134         read(W[i]);
135     }
136     for(int i = 1, x, y; i < n; i++) {
137         read(x);
138         read(y);
139         add(x, y);
140         add(y, x);
141     }
142     for(int i = 1; i <= n; i++) {
143         read(col[i]);
144     }
145 
146     DFS(1, 0);
147     for(int i = 2; i <= n; i++) {
148         pw[i] = pw[i >> 1] + 1;
149     }
150     for(int j = 1; j <= pw[n]; j++) {
151         for(int i = 1; i <= n; i++) {
152             fa[i][j] = fa[fa[i][j - 1]][j - 1];
153         }
154     }
155 
156     for(int i = 1, f, x, y; i <= q; i++) {
157         read(f);
158         read(x);
159         read(y);
160         if(!f) { // change
161             ++topc;
162             change[topc].p = x;
163             change[topc].x = y;
164             change[topc].t = i;
165         }
166         else { // ask
167             ++topa;
168             if(first[x] > first[y]) {
169                 std::swap(x, y);
170             }
171             int z = lca(x, y);
172             if(z == x) {
173                 ask[topa].l = first[x];
174                 ask[topa].r = first[y];
175             }
176             else {
177                 ask[topa].l = last[x];
178                 ask[topa].r = first[y];
179                 ask[topa].ex = z;
180             }
181             ask[topa].t = i;
182         }
183     }
184     for(int i = 1; i <= n * 2; i++) {
185         fr[i] = (i - 1) / T + 1;
186     }
187     std::sort(ask + 1, ask + topa + 1);
188 
189     int l = 1, r = 1, time = 0;
190     work(1);
191     for(int i = 1; i <= topa; i++) {
192         while(ask[i].l < l) {
193             work(--l);
194         }
195         while(r < ask[i].r) {
196             work(++r);
197         }
198         while(l < ask[i].l) {
199             work(l++);
200         }
201         while(ask[i].r < r) {
202             work(r--);
203         }
204         while(change[time].t > ask[i].t) {
205             bool f = *(vis + change[time].p);
206             if(f) {
207                 del(change[time].p);
208             }
209             *(col + change[time].p) = change[time].last;
210             if(f) {
211                 add(change[time].p);
212             }
213             time--;
214         }
215         while(time < topc && change[time + 1].t <= ask[i].t) {
216             time++;
217             bool f = *(vis + change[time].p);
218             change[time].last = *(col + change[time].p);
219             if(f) {
220                 del(change[time].p);
221             }
222             *(col + change[time].p) = change[time].x;
223             if(f) {
224                 add(change[time].p);
225             }
226         }
227         if(ask[i].ex) {
228             add(ask[i].ex);
229         }
230         ask[i].ans = ans;
231         if(ask[i].ex) {
232             del(ask[i].ex);
233         }
234     }
235 
236     std::sort(ask + 1, ask + topa + 1, cmp);
237     for(int i = 1; i <= topa; i++) {
238         printf("%lld\n", ask[i].ans);
239     }
240     return 0;
241 }
AC代码

回滚莫队:解决不好删除,只能增加的莫队。

例:歴史の研究 

posted @ 2018-12-26 19:16  huyufeifei  阅读(...)  评论(...编辑  收藏