虚树学习

大概入门了一下虚树, 感觉虚树其实就是对暴力dfs的优化, 只保留了些有效信息的点, 最后用栈模拟dfs.

板子题 洛谷 P2495 

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#define pb push_back
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;
typedef long long ll;

const int N = 4e5+10, INF = 0x7f7f7f7f;
int n, m;
int L[N], R[N], dep[N];
int vis[N], tr[N<<2], mi[N];
int fa[N][25];
ll sum[N];
vector<int> s;
struct _ {int to,w;};
vector<_> g[N];

void dfs(int x, int f) {
	L[x] = ++*L, fa[x][0] = f;
	for (int i=1; fa[x][i-1]; ++i) {
		fa[x][i] = fa[fa[x][i-1]][i-1];
	}
	for (auto e:g[x]) if (e.to!=f) {
		int y = e.to;
		mi[y] = min(mi[x], e.w);
		dep[y] = dep[x]+1;
		dfs(y, x);
	}
	R[x] = ++*L;
}

int lca(int x, int y) {
    if(dep[x]<dep[y]) swap(x,y);
	PER(i,0,20) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
	if (x==y) return x;
	PER(i,0,20) if (fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i];
	return fa[x][0];
}

bool cmp(int x, int y) {
	int k1=(x>0?L[x]:R[-x]);
	int k2=(y>0?L[y]:R[-y]);
	return k1<k2;
}

int main() {
	scanf("%d", &n);
	REP(i,2,n) {
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		g[u].pb({v,w});
		g[v].pb({u,w});
	}
	mi[1] = INF, dep[1]=1, dfs(1,0);
	scanf("%d", &m);
	while (m--) {
		scanf("%d", tr);
		REP(i,1,*tr) {
			scanf("%d", tr+i);
			vis[tr[i]] = 1;
			sum[tr[i]] = mi[tr[i]];
		}
		sort(tr+1,tr+1+*tr,cmp);
		REP(i,1,*tr-1) {
			int x = lca(tr[i],tr[i+1]);
			if (!vis[x]) {
				tr[++*tr] = x;
				vis[x] = 1;
			}
		}
		if (!vis[1]) tr[++*tr]=1;
		int t = *tr;
		REP(i,1,t) tr[++*tr]=-tr[i];
		sort(tr+1,tr+1+*tr,cmp);
		REP(i,1,*tr) {
			if (tr[i]>0) { 
				s.push_back(tr[i]);
				continue;
			}
			int x = s.back();s.pop_back();
			if (x==1) printf("%lld\n", sum[1]);
			else {
				int f = s.back();
				sum[f] += min(sum[x], (ll)mi[x]);
			}
			sum[x] = 0, vis[x] = 0;
		}
	}
}

猜你喜欢

转载自www.cnblogs.com/uid001/p/10414960.html