题目大意:树上白点最长距离。。。修改点颜色。。。
大致做法就是边分治,边的两边维护最长距离记子边答案,一路更新,一次操作 O(logn * logn) (堆和树高)。。。
写一写这种题真心锻炼代码能力。。。各种大常数不然调试不能。。。
lyp 把 kAc 卡成 WA30 的神级数据都可以过,但是始终交不过 spoj。。。期待有更新。。。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
using namespace std;
#define FOR(i, j, k) for (i = (j); i <= (k); ++ i)
#define ROF(i, j, k) for (i = (j); i >= (k); -- i)
#define FER(i, j, k) for (i = j[k]; i; i = i->n)
#define maxn 200005
int vessle[maxn * 21], * head = vessle, temp;
int * new_array(int size) {return (head += size) - size;}
struct heap {
int * h, tot;
heap (int size) {h = new_array(size + 1), tot = 0;}
void up(int), down(int), push(int), pop(int);
int top();
};
struct da {int s, t, w; da * n, * f, * l, * r; heap * h; int maxi;};
da das[maxn * 2], * adj = das + 1, * edge[maxn];
struct ed {int t, w; ed * n;};
ed eds[maxn], * adj0 = eds, * edge0[maxn];
int n, Q, size, result; da * centre;
int deg[maxn], mark[maxn];
int dist[21][maxn], posi[21][maxn];/*too small*/
int * dis, * pos; heap * he;
da * father[maxn]; bool color[maxn];
void heap :: up(int p)
{
for (; p >> 1 && dis[h[p]] > dis[h[p >> 1]]; p >>= 1)
swap(h[p], h[p >> 1]), pos[h[p]] = p;
pos[h[p]] = p;
}
void heap :: down(int p)
{
for (int q; p << 1 <= tot; p = q)
{
if (p << 1 == tot) q = tot;
else if (dis[h[p << 1]] > dis[h[p << 1 | 1]])
q = p << 1; else q = p << 1 | 1;
if (dis[h[q]] > dis[h[p]]) swap(h[q], h[p]), pos[h[p]] = p;
else break;
}
pos[h[p]] = p;
}
void heap :: push(int k) {h[++ tot] = k; pos[k] = tot; up(tot);}
void heap :: pop(int k)
{
h[pos[k]] = h[tot], pos[h[tot]] = pos[k], -- tot, down(pos[k]);
}
int heap :: top() {return dis[h[1]];}
int dfs3(da * fr)
{
int res = 1; da * e;
if (he && ! color[fr->t]) he->push(fr->t);
FER (e, edge, fr->t) if (! e->h && e->t != fr->s)
dis[e->t] = dis[fr->t] + e->w, res += dfs3(e);
if (min(res, size - res) > min(result, size - result))
result = res, centre = fr;
return res;
}
void update(da * fr)
{
fr->maxi = max(fr->l->maxi, fr->r->maxi);
if (fr->l->h->tot && fr->r->h->tot)
fr->maxi = max(fr->maxi, fr->l->h->top() + fr->l->w + fr->r->h->top());
}
void divide(da * fr, int dep)
{
dis = dist[dep], pos = posi[dep], he = fr->h;
if (size <= 1)
{
if (color[fr->t]) return;
father[fr->t] = fr, mark[fr->t] = dep, he->push(fr->t);
return;
}
result = 0, dfs3(fr);
da * c1 = centre, * c2 = das + ((c1 - das) ^ 1);
int s1 = result, s2 = size - result;
c1->h = new heap(s1), c2->h = new heap(s2);
c1->f = c2->f = fr, fr->l = c1, fr->r = c2;
size = s1, divide(c1, dep + 1);
size = s2, divide(c2, dep + 1);
update(fr), dis = dist[dep];
}
void dfs2(int u)
{
ed * e;
if (deg[u] > 2)
{
edge0[++ n] = edge0[u]->n, edge0[u]->n = 0;/*too much*/
* (++ adj0) = (ed) {n, 0, edge0[u]}, edge0[u] = adj0;
deg[n] = deg[u] - 1, deg[u] = 2, color[n] = 1;
}
FER (e, edge0, u)
{
* (++ adj) = (da) {u, e->t, e->w, edge[u]}, edge[u] = adj;
* (++ adj) = (da) {e->t, u, e->w, edge[e->t]}, edge[e->t] = adj;
dfs2(e->t);
}
}
void dfs1(int u, int fa)
{
da * e;
FER (e, edge, u) if (e->t != fa)
{
* (++ adj0) = (ed) {e->t, e->w, edge0[u]}, edge0[u] = adj0;
++ deg[u], dfs1(e->t, u);
}
}
int main()
{
int i, j, k, l, total;
scanf("%d", & n), total = n;
FOR (i, 2, n)
{
scanf("%d%d%d", & j, & k, & l);
* (++ adj) = (da) {j, k, l, edge[j]}, edge[j] = adj;
* (++ adj) = (da) {k, j, l, edge[k]}, edge[k] = adj;
}
dfs1(1, 0);
memset(edge, 0, sizeof edge), adj = das + 1;
dfs2(1);
* (++ adj) = (da) {0, 1}, size = n, divide(adj, 0);
for (scanf("%d\n", & Q); Q --; getchar())
if (getchar() == 'A')
if (total) printf("%d\n", adj->maxi);
else puts("They have disappeared.");
else
{
scanf("%d", & i);
bool b = color[i] = ! color[i];
b ? -- total : ++ total, j = mark[i];
for (da * e = father[i]; e != adj; update(e = e->f), -- j)
{
dis = dist[j], pos = posi[j];
b ? e->h->pop(i) : e->h->push(i);
}
}
return 0;
}