SPOJ - COT2

Posted p0ny^v^

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ - COT2相关的知识,希望对你有一定的参考价值。

SPOJ - COT2 

首先容咱吐槽一下,这spoj跟bzoj一个尿性,RE显示成WA,害的咱弄了近一个小时。

题意:一颗树上每个点都有一个权值$v$,求一条路径上权值的种数。

题解:树上莫队。

首先咱dfs一下,记录这棵树的欧拉序$f$(就是进入的时候记录,出去的时候再记录的那种)。这样就把莫队在树上的转移变成了在欧拉序上的转移。

那么如何支持对$u-v$的查询呢?

先想想用欧拉序做一棵有边权树的链上求和怎么做到。

咱记$dis_i$为$i$到根节点的距离,那么$u-v$的答案就是$dis_u+dis_v-2*dis_{lca}$。

这个其实也类似。如果当前转移到的区间是$[l,r]$,其中节点$u$出现$0$或$2$次,咱不算$v_u$,出现$1$次才算。

再来说说查询的节点$u$和$v$在欧拉序上的区间$[l,r]$是怎么得到的。

记$I_i$,$O_i$分别为进入和离开$i$的时间。不妨设$I_u < I_v$。

如果$u=lca(u,v)$,那么区间就是$[I_u, I_v]$($[O_v,O_u]$是一样的)。

如果$u \neq lca(u,v)$,那么区间就是$[O_u, I_v] + [I_{lca},I_{lca}]$。

代码写的很$ugly$,可能会再写一个比较$beautiful$的。

  1 #include<cassert>
  2 #include<map>
  3 #include<cmath>
  4 #include<vector>
  5 #include<cstdio>
  6 #include<iostream>
  7 #include<algorithm>
  8 #define pb push_back
  9 using namespace std;
 10 inline char nc() {
 11     static char b[1<<14],*s=b,*t=b;
 12     return s==t&&(t=(s=b)+fread(b,1,1<<14,stdin),s==t)?-1:*s++;
 13 }
 14 inline void read(int &x) {
 15     char b = nc(); x = 0;
 16     for (; !isdigit(b); b = nc());
 17     for (; isdigit(b); b = nc()) x = x * 10 + b - 0;
 18 }
 19 const int N = 40010;
 20 int n, m, val[N], H;
 21 map < int , int > h;
 22 vector < int > g[N];
 23 inline int idx(int t) {
 24     return h.count(t) ? h[t] : h[t] = ++H;    
 25 }
 26 inline void ae(int u, int v) {
 27     g[u].pb(v); g[v].pb(u);
 28 }
 29 int D, I[N], O[N], f[N*2], S;
 30 int fa[N], son[N], dep[N], sz[N], top[N];
 31 void dfs1(int u, int f) {
 32     sz[u] = 1; fa[u] = f; dep[u] = dep[f] + 1;
 33     for (int i = 0, v; i < g[u].size(); ++i) if ((v = g[u][i]) != f) {
 34         dfs1(v, u); sz[u] += sz[v];
 35         if (sz[son[u]] < sz[v]) son[u] = v;
 36     }
 37 }
 38 void dfs2(int u, int tp) {
 39     I[u] = ++D;
 40     top[u] = tp; if (son[u]) dfs2(son[u], tp);
 41     for (int v, i = 0; i < g[u].size(); ++i)
 42         if (v = g[u][i], v != fa[u] && v != son[u]) dfs2(v, v);
 43     O[u] = ++D;
 44 }
 45 int findLca(int a, int b) {
 46     for (; top[a] != top[b]; a = fa[top[a]])
 47         if (dep[top[a]] < dep[top[b]]) swap(a, b);
 48     return dep[a] < dep[b] ? a : b;
 49 }
 50 struct Node {
 51     int l, r, id, e;
 52     inline void init(int u, int v, int i) {
 53         if (I[u] > I[v]) swap(u, v);
 54         int lca = findLca(u, v);
 55         if (u == lca) l = I[u], r = I[v], e = 0;
 56         else r = O[u], l = I[v], e = lca;
 57         if (l > r) swap(l, r); id = i;
 58 
 59     }
 60     inline bool operator<(const Node &o) const {
 61         return (l / S < o.l / S) || (l / S == o.l / S && r < o.r);
 62     }
 63 } q[100010];
 64 int cnt[N], tans, oc[N], ans[100010];
 65 inline void add(int x) {
 66     if (++cnt[x] == 1) ++tans;
 67 }
 68 inline void del(int x) {
 69     if (--cnt[x] == 0) --tans;    
 70 }
 71 int main() {
 72     read(n); read(m); S = sqrt(n * 2);
 73     for (int t, i = 1; i <= n; ++i)
 74         read(t), val[i] = idx(t);
 75     for (int i = 1, u, v; i < n; ++i)
 76         read(u), read(v), ae(u, v);
 77     dfs1(1, 0); dfs2(1, 1);
 78     for (int i = 1; i <= n; ++i) f[I[i]] = f[O[i]] = i;
 79     for (int u, v, i = 0; i < m; ++i) 
 80         read(u), read(v), q[i].init(u, v, i);
 81     sort(q, q + m); add(f[1]); ++oc[f[1]];
 82     for (int i = 0, l = 1, r = 1; i < m; ++i) {
 83         while (r < q[i].r) {
 84             int u = f[++r];
 85             assert(oc[u] != 2);
 86             if (oc[u] == 1) del(val[u]);
 87             else add(val[u]);
 88             ++oc[u];
 89         }
 90         while (r > q[i].r) {
 91             int u = f[r--];
 92             assert(oc[u] != 0);
 93             if (oc[u] == 1) del(val[u]);
 94             else add(val[u]);
 95             --oc[u];
 96         }
 97         while (l < q[i].l) {
 98             int u = f[l++];
 99             assert(oc[u] != 0);
100             if (oc[u] == 1) del(val[u]);
101             else add(val[u]);
102             --oc[u];
103         }
104         while (l > q[i].l) {
105             int u = f[--l];
106             assert(oc[u] != 2);
107             if (oc[u] == 1) del(val[u]);
108             else add(val[u]);
109             ++oc[u];
110         }
111         ans[q[i].id] = tans;
112         if (q[i].e && cnt[val[q[i].e]] == 0) ++ans[q[i].id];
113         /*
114         if (q[i].lca != q[i].u && cnt[val[q[i].lca]] == 0) ++cnt[val[q[i].lca]];
115         for (int j = 1; j <= H; ++j) printf("%d ", cnt[j]); puts("");
116         if (q[i].lca != q[i].u && cnt[val[q[i].lca]] == 0) --cnt[val[q[i].lca]];
117         puts("OC BEGIN");
118         for (int j = 1; j <= n; ++j) printf("%d ", oc[j]); 
119         puts("OC END");
120         */
121     }
122     for (int i = 0; i < m; ++i) printf("%d\n", ans[i]);
123     return 0;
124 }

 

以上是关于SPOJ - COT2的主要内容,如果未能解决你的问题,请参考以下文章

SPOJ - COT2

SPOJ10707 COT2 - Count on a tree II 树上莫队

SPOJ - COT2 Count on a tree II

SPOJ - COT2 离线路径统计

SPOJ:COT2 Count on a tree II

SPOJ - COT2 Count on a tree II