[洛谷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
*/
posted @ 2022-04-06 11:01  皮皮刘  阅读(29)  评论(0编辑  收藏  举报