題目鏈接 SP2666 QTREE4 - Query on a tree IV
給定一棵 n 個點的帶邊權的樹,點從 1 到 n 編號。每個點可能有兩種顏色:黑或白。我們定義 dist(a,b) 爲點 a 至點 b 路徑上的權值之和。
一開始所有的點都是白色的。
要求作以下操作:
C a
將點 a 的顏色反轉。(黑變白,白變黑)
A
詢問 dist(a,b) 的最大值。a,b 點都必須爲白色(a 與 b 可以相同),顯然如果樹上仍存在白點,查詢得到的值一定是個非負數。
特別地,如果 A
操作時樹上沒有白點,輸出 They have disappeared.
。
對於100% 的數據,N \leq 100000,Q \leq 100000,-10^3 \leq c \leq 10^3。
這道題跟[ZJOI2007]捉迷藏【動態點分治】在做法上有異曲同工之處,只是邊不再是單位長度,而是給出了對應的邊長,同時邊長可以爲負數。
這道題用動態點分治的做法,容易被卡時限,可以考慮使用快讀來加速讀入,因爲輸入真的很大。
然後,正如我們所知道的,我們不妨考慮經過一個點的最遠到達和次遠到達,來確定直徑的長度,然後,也有可能是到自己就是作爲一個次遠到達來完成這個。
所以,每一個結點要用一個堆來記錄它的子結點到它的父節點的距離值。
這裏講幾個細節上的東西:
- 處理都是在點分樹上進行處理的;
- 只有對下面結點的距離數量大於等於2的時候,纔有可能產生答案;
- 我們在更新答案之前,要刪除舊的答案的影響;
- 不要忘記形成的直徑可能是自己和自己所能到達的最遠距離;
- 最初給ans要push一個0,因爲答案不允許是負數;
- 同時,如果黑點的數量==N的時候,不要忘記按要求輸出。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define Big_INF 0x3f3f3f3f3f3f3f3f
#define eps 1e-6
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
inline int read()
{
int x=0, r = 1; char c = getchar();
while (c < '0' || c > '9') { if(c == '-') r = -1; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * r;
}
const int maxN = 2e5 + 7;
int N, Q, head[maxN], cnt, LOG_2[maxN << 1];
struct Eddge
{
int nex, to; int val;
Eddge(int a=-1, int b=0, int c=0):nex(a), to(b), val(c) {}
} edge[maxN << 1];
inline void addEddge(int u, int v, int w)
{
edge[cnt] = Eddge(head[u], v, w);
head[u] = cnt++;
}
inline void _add(int u, int v, int w) { addEddge(u, v, w); addEddge(v, u, w); }
struct Grand_Father
{
int deep[maxN], euler[maxN << 1], Esiz, rid[maxN]; int dis[maxN];
void dfs(int u, int fa)
{
deep[u] = deep[fa] + 1; rid[u] = Esiz + 1;
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == fa) continue;
dis[v] = dis[u] + edge[i].val;
euler[++Esiz] = u;
dfs(v, u);
}
euler[++Esiz] = u;
}
int mn[maxN << 1][20];
inline void RMQ_Init()
{
for(int i=1; i<=Esiz; i++) mn[i][0] = euler[i];
for(int j=1; (1 << j) <= Esiz; j++)
{
for(int i=1; i + (1 << j) - 1 <= Esiz; i++)
{
if(deep[mn[i][j - 1]] < deep[mn[i + (1 << (j - 1))][j - 1]]) mn[i][j] = mn[i][j - 1];
else mn[i][j] = mn[i + (1 << (j - 1))][j - 1];
}
}
}
inline int Rmq(int l, int r)
{
int det = r - l + 1, kk = LOG_2[det];
if(deep[mn[l][kk]] <= deep[mn[r - (1 << kk) + 1][kk]]) return mn[l][kk];
else return mn[r - (1 << kk) + 1][kk];
}
inline int _LCA(int u, int v)
{
int l = rid[u], r = rid[v];
if(l > r) swap(l, r);
return Rmq(l, r);
}
inline int _Dis(int u, int v)
{
int lca = _LCA(u, v);
return dis[u] + dis[v] - 2 * dis[lca];
}
} A_lca;
struct heap
{
priority_queue<int> Que, Del;
inline bool empty()
{
while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
return Que.empty();
}
inline void push(int val) { Que.push(val); }
inline void clear(int val) { Del.push(val); }
inline int size() { return (int)(Que.size() - Del.size()); }
inline int top()
{
while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
return Que.top();
}
inline void pop()
{
while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
Que.pop();
}
inline int Fir_Sec()
{
int s[2] = {0};
if(!empty()) s[0] = top();
pop();
if(!empty()) s[1] = top();
push(s[0]);
return s[0] + s[1];
}
} ans, s[maxN][2];
int black_num = 0;
int siz[maxN], all, son[maxN], maxx, root, father[maxN];
bool vis[maxN] = {false};
void findroot(int u, int fa)
{
siz[u] = 1; son[u] = 0;
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(vis[v] || v == fa) continue;
findroot(v, u);
siz[u] += siz[v];
son[u] = max(son[u], siz[v]);
}
son[u] = max(son[u], all - siz[u]);
if(son[u] < maxx) { maxx = son[u]; root = u; }
}
void Get_dis(int u, int fa)
{
s[root][0].push(A_lca._Dis(u, father[root]));
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(vis[v] || v == fa) continue;
Get_dis(v, u);
}
}
void Divide(int u)
{
vis[u] = true;
if(father[u]) Get_dis(u, 0);
int totsiz = all;
for(int i=head[u], v, rt; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(vis[v]) continue;
all = siz[v] > siz[u] ? totsiz - siz[u] : siz[v];
maxx = INF;
findroot(v, 0);
father[root] = u;
rt = root;
Divide(root);
s[u][1].push(s[rt][0].top());
}
s[u][1].push(0);
if(s[u][1].size() >= 2) ans.push(s[u][1].Fir_Sec());
}
bool black[maxN] = {false};
void turn(int u)
{
int p, cop_u = u; int df, das;
black[u] ^= 1;
if(black[u])
{
black_num ++;
if(s[u][1].size() >= 2) ans.clear(s[u][1].Fir_Sec());
s[u][1].clear(0);
if(s[u][1].size() >= 2) ans.push(s[u][1].Fir_Sec());
p = father[u];
while(p)
{
df = A_lca._Dis(cop_u, p);
if(s[p][1].size() >= 2)
{
das = s[p][1].Fir_Sec();
ans.clear(das);
}
s[p][1].clear(s[u][0].top());
s[u][0].clear(df);
if(!s[u][0].empty()) s[p][1].push(s[u][0].top());
if(s[p][1].size() >= 2)
{
das = s[p][1].Fir_Sec();
ans.push(das);
}
u = p;
p = father[u];
}
}
else
{
black_num --;
if(s[u][1].size() >= 2) ans.clear(s[u][1].Fir_Sec());
s[u][1].push(0);
if(s[u][1].size() >= 2) ans.push(s[u][1].Fir_Sec());
p = father[u];
while(p)
{
df = A_lca._Dis(cop_u, p);
if(s[p][1].size() >= 2)
{
das = s[p][1].Fir_Sec();
ans.clear(das);
}
if(!s[u][0].empty()) s[p][1].clear(s[u][0].top());
s[u][0].push(df);
s[p][1].push(s[u][0].top());
if(s[p][1].size() >= 2)
{
das = s[p][1].Fir_Sec();
ans.push(das);
}
u = p;
p = father[u];
}
}
}
inline void init()
{
cnt = 0; ans.push(0);
for(int i=1; i<=N; i++) head[i] = -1;
for(int i = 1, j = 2, k = 0; i<=(N << 1); i++)
{
if(i == j) { j <<= 1; k ++; }
LOG_2[i] = k;
}
}
int main()
{
N = read();
init();
for(int i=1, u, v, w; i<N; i++)
{
u = read(); v = read(); w = read();
_add(u, v, w);
}
A_lca.dfs(1, 0);
A_lca.RMQ_Init();
all = N; maxx = INF;
findroot(1, 0);
Divide(root);
scanf("%d", &Q);
char op[3]; int x;
while(Q--)
{
scanf("%s", op);
if(op[0] == 'A')
{
if(black_num == N) printf("They have disappeared.\n");
else printf("%d\n", ans.top());
}
else
{
x = read();
turn(x);
}
}
return 0;
}