1095: [ZJOI2007]Hide 捉迷藏
1095: [ZJOI2007]Hide 捉迷藏
分析:
动态点分治。Qtree4没过。。。
先建出点分树,然后每个点维护两个堆,一个h1表示当前根的连通块内,所有点到点分树上父节点的距离,h2表示当前根的所有子节点的h1的最大值。
更新的时候,深度是log的,暴力修改堆中的元素即可。
代码:
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> #include<bitset> #define fore(i, u, v) for (int i = head[u], v = e[i].to; i; i = e[i].nxt, v = e[i].to) using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 200005; struct Edge { int to, nxt, w; } e[N << 1]; int head[N], dep[N], f[N][20], Log[N], pos[N], siz[N], fa[N]; bool vis[N], col[N]; int n, En, Mn, Root, Index, Size; struct Heap{ priority_queue<int> h, d; inline void Insert(int x) { h.push(x); } inline void Delete(int x) { d.push(x); } inline int Size() { return h.size() - d.size(); } inline void Fix() { while (d.size() && h.top() == d.top()) h.pop(), d.pop(); } inline int Top() { Fix(); return h.top(); } inline int Sec() { Fix(); int t1 = h.top(), t2; h.pop(); Fix(); t2 = h.top(); h.push(t1); return t2; } // 取次大值之前也要fix一下 void Change(int x,bool f) { f ? Delete(x) : Insert(x); } void pr() { } }h1[N], h2[N], Ans; inline void add_edge(int u,int v,int w) { ++En; e[En].nxt = head[u], e[En].to = v, e[En].w = w; head[u] = En; ++En; e[En].nxt = head[v], e[En].to = u, e[En].w = w; head[v] = En; } void predfs(int u,int fa) { pos[u] = ++Index; f[Index][0] = dep[u]; fore(i, u, v) if (v != fa) dep[v] = dep[u] + e[i].w, predfs(v, u), f[++Index][0] = dep[u]; } void prermq() { for (int i = 2; i <= Index; ++i) Log[i] = Log[i >> 1] + 1; for (int j = 1; j <= Log[Index]; ++j) for (int i = 1; i + (1 << j) - 1 <= Index; ++i) f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); } void getroot(int u,int fa) { int mx = 0; siz[u] = 1; fore(i, u, v) if (!vis[v] && v != fa) { getroot(v, u); siz[u] += siz[v]; siz[v] > mx ? mx = siz[v] : mx; } mx = max(mx, Size - siz[u]); if (mx < Mn) Mn = mx, Root = u; } void dfs(int u,int fa,int d,Heap &A) { A.Insert(d); fore(i, u, v) if (!vis[v] && v != fa) dfs(v, u, d + e[i].w, A); } void Add(Heap &A) { if (A.Size() >= 2) Ans.Insert(A.Top() + A.Sec()); } void Del(Heap &A) { if (A.Size() >= 2) Ans.Delete(A.Top() + A.Sec()); } void solve(int u) { vis[u] = 1, h2[u].Insert(0); fore(i, u, v) if (!vis[v]) { Heap tmp; dfs(v, u, e[i].w, tmp); Mn = 1e9, Size = siz[v], getroot(v, u); fa[Root] = u; h1[Root] = tmp, h2[u].Insert(tmp.Top()); solve(Root); } Add(h2[u]); } int LCA(int x,int y) { if (pos[x] > pos[y]) swap(x, y); int k = Log[pos[y] - pos[x] + 1]; return min(f[pos[x]][k], f[pos[y] - (1 << k) + 1][k]); // !!! } int getdis(int x,int y) { return dep[x] + dep[y] - 2 * LCA(x, y); } void update(int x,bool f) { Del(h2[x]), h2[x].Change(0, f), Add(h2[x]); for (int now = x; fa[now]; now = fa[now]) { Del(h2[fa[now]]); if (h1[now].Size()) h2[fa[now]].Delete(h1[now].Top()); h1[now].Change(getdis(x, fa[now]), f); if (h1[now].Size()) h2[fa[now]].Insert(h1[now].Top()); Add(h2[fa[now]]); } } char getc() { char ch = getchar(); for (; ch != 'G' && ch != 'C'; ch = getchar()); return ch; } int main() { n = read(); for (int u, v, w, i = 1; i < n; ++i) u = read(), v = read(), add_edge(u, v, 1); predfs(1, 0); prermq(); Mn = 1e9, Size = n, getroot(1, 0); solve(Root); int m = read(), White = n, x; char opt[5]; while (m --) { if (getc() == 'C') x = read(), update(x, col[x] ^= 1), White += col[x] ? -1 : 1; else if (!White) puts("They have disappeared."); else printf("%d\n", White > 1 ? max(0, Ans.Top()) : 0); } return 0; }