[洛谷P4115] Qtree4 & [ZJOI2007] 捉迷藏
前言
有个地方没考虑到能过弱化版,我直接【流汗】。
题目
讲解
这是一个没什么技术含量的 \(O(n\log_2^2n)\) 的点分+堆的做法。
首先你需要实现可删堆,原理就是用两个堆,一个是用的堆,一个是需要删的数存的堆,每次取把他们相同的堆定弹完再取。
建立点分树,对于点分树上的点 \(x\),我们维护两个堆:
- \(h1_x\),维护 \(x\) 子树内的白点到 \(father_x\) 的距离。
- \(h2_x\),维护 \(x\) 的所有儿子的 \(h1\) 的堆顶元素,也就是所有的 \(h1_{son_x}\) 的堆顶元素,如果 \(x\) 本身是白点,那么还需要放一个 \(0\) 进去。
由于弱化版数据太水,我最开始没放 \(0\) 都能过,但是这道题会在第 \(21\) 组 \(\tt \color{red}{WA}\)。
最后维护的就是表示答案的堆 \(ans\),里面维护的是每个 \(h2_x\) 的堆顶的两个元素的和。
代码相当好实现,注意这道题距离要对 \(0\) 取 \(\max\),以及没有白点输出 They have disappeared.
。
代码
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 200005;
const int INF = 0x3f3f3f3f;
int n;
bool tag[MAXN];
LL Read()
{
LL x = 0,f = 1;char c = getchar();
while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
char gc(){
char c = getchar();
while(c != 'C' && c != 'A') c = getchar();
return c;
}
int head[MAXN],tot;
struct edge{
int v,w,nxt;
}e[MAXN<<1];
void Add_Edge(int u,int v,int w){
e[++tot] = edge{v,w,head[u]};
head[u] = tot;
}
void Add_Double_Edge(int u,int v,int w){
Add_Edge(u,v,w);
Add_Edge(v,u,w);
}
int st[MAXN][18],eltot,d[MAXN],LG[MAXN],who[MAXN],wdwd[MAXN];
void dfs1(int x,int fa){
wdwd[x] = wdwd[fa] + 1; st[who[x] = ++eltot][0] = x;
for(int i = head[x],v; i ;i = e[i].nxt){
if((v = e[i].v) == fa) continue;
d[v] = d[x] + e[i].w; dfs1(v,x); st[++eltot][0] = x;
}
}
int calc(int x,int y){return wdwd[x] < wdwd[y] ? x : y;}
int lca(int x,int y){
if(x == y) return x;
x = who[x]; y = who[y];
if(x > y) swap(x,y);
int k = LG[y-x+1];
return calc(st[x][k],st[y-(1<<k)+1][k]);
}
int dis(int x,int y){return d[x] + d[y] - (d[lca(x,y)] << 1);}
struct hp{
priority_queue<int> q,de;
void doit(){while(!de.empty() && q.top() == de.top()) q.pop(),de.pop();}
int tp(){doit();if(q.size()) return q.top(); return -INF;}
void ps(int x){if(x != -INF) q.push(x);}
void del(int x){if(x != -INF) de.push(x);}
int sz(){return q.size()-de.size();}
int top2(){
if(q.size()-de.size() <= 1) return -INF;
doit(); int ret = q.top(),one = ret; q.pop();
doit(); ret += q.top(); q.push(one);
return ret;
}
}h1[MAXN],h2[MAXN],ans;
int rt,f[MAXN],siz[MAXN],MAX[MAXN];
bool vis[MAXN];
void getrt(int x,int fa,int S){
siz[x] = 1; MAX[x] = 0;
for(int i = head[x],v; i ;i = e[i].nxt){
if(vis[v = e[i].v] || v == fa) continue;
getrt(v,x,S); siz[x] += siz[v]; MAX[x] = Max(MAX[x],siz[v]);
}
MAX[x] = Max(MAX[x],S-siz[x]);
if(!rt || MAX[x] < MAX[rt]) rt = x;
}
void getsiz(int x,int fa){
siz[x] = 1; if(f[rt]) h1[rt].ps(dis(f[rt],x));
for(int i = head[x],v; i ;i = e[i].nxt){
if(vis[v = e[i].v] || v == fa) continue;
getsiz(v,x); siz[x] += siz[v];
}
}
void dfs2(int x){
vis[x] = 1; getsiz(x,0); h2[x].ps(0); if(f[x]) h2[f[x]].ps(h1[x].tp());
for(int i = head[x],v; i ;i = e[i].nxt){
if(vis[v = e[i].v]) continue;
rt = 0; getrt(v,0,siz[v]); f[rt] = x; dfs2(rt);
}
if(h2[x].sz() > 1) ans.ps(h2[x].top2());
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read();
for(int i = 1,u,v;i < n;++ i) u = Read(),v = Read(),Add_Double_Edge(u,v,Read());
dfs1(1,0);
for(int i = eltot;i >= 1;-- i)
for(int j = 1;i+(1<<j)-1 <= eltot;++ j)
st[i][j] = calc(st[i][j-1],st[i+(1<<(j-1))][j-1]);
LG[0] = -1;
for(int i = 1;i <= eltot;++ i) LG[i] = LG[i>>1] + 1;
getrt(1,0,n); dfs2(rt);
int cnt = n;
for(int Q = Read(); Q ;-- Q){
if(gc() == 'C'){
int pos = Read(),now = pos;
if(tag[pos] ^= 1) --cnt;
else ++cnt;
if(tag[pos]){//delete
ans.del(h2[now].top2());
h2[now].del(0);
ans.ps(h2[now].top2());
while(f[now]){
ans.del(h2[f[now]].top2());
h2[f[now]].del(h1[now].tp());
h1[now].del(dis(f[now],pos));
h2[f[now]].ps(h1[now].tp());
ans.ps(h2[f[now]].top2());
now = f[now];
}
}
else{//add
ans.del(h2[now].top2());
h2[now].ps(0);
ans.ps(h2[now].top2());
while(f[now]){
ans.del(h2[f[now]].top2());
h2[f[now]].del(h1[now].tp());
h1[now].ps(dis(f[now],pos));
h2[f[now]].ps(h1[now].tp());
ans.ps(h2[f[now]].top2());
now = f[now];
}
}
}
else{
if(ans.sz()) Put(Max(0,ans.tp()),'\n');
else if(cnt) Put(0,'\n');
else printf("They have disappeared.\n");
}
}
return 0;
}
/*
poor English time!
h1[x] : the distance between fa_x and son_x
h2[x] : the top elements of h1[son_x]
ans : the sum of two top elements in h2[x]
print : the top element of ans
*/