• 虚树(Bzoj3611: [Heoi2014]大工程)


    题面

    传送门

    虚树

    把跟询问有关的点拿出来建树,为了方便树(DP)
    (LCA)处要合并答案,那么把这些点的(LCA)也拿出来

    做法:把点按(dfs)序排列,然后求出相邻两个点的(LCA),把这些点建一个虚树,维护一个栈就好了

    Sol

    虚树+树(DP)

    # include <bits/stdc++.h>
    # define IL inline
    # define RG register
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    
    IL int Input(){
    	RG int x = 0, z = 1; RG char c = getchar();
    	for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    	for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    	return x * z;
    }
    
    const int maxn(1e6 + 5);
    const int inf(1e9);
    
    int n, first1[maxn], cnt, first2[maxn], id[maxn], p[maxn];
    ll g[maxn], f[maxn], num[maxn], sum, mx, mn, tot;
    int dfn[maxn], size[maxn], son[maxn], fa[maxn];
    int s[maxn], top[maxn], idx, deep[maxn];
    
    struct Edge{
    	int to, next;
    } e2[maxn << 1], e1[maxn << 1];
    
    IL void Add1(RG int u, RG int v){
    	e1[cnt] = (Edge){v, first1[u]}, first1[u] = cnt++;
    }
    
    IL void Add2(RG int u, RG int v){
    	e2[cnt] = (Edge){v, first2[u]}, first2[u] = cnt++;
    }
    
    IL void Dfs1(RG int u){
    	size[u] = 1;
    	for(RG int e = first1[u]; e != -1; e = e1[e].next){
    		RG int v = e1[e].to;
    		if(!size[v]){
    			deep[v] = deep[u] + 1;
    			Dfs1(v), size[u] += size[v], fa[v] = u;
    			if(size[v] > size[son[u]]) son[u] = v;
    		}
    	}
    }
    
    IL void Dfs2(RG int u, RG int tp){
    	top[u] = tp, dfn[u] = ++idx;
    	if(son[u]) Dfs2(son[u], tp);
    	for(RG int e = first1[u]; e != -1; e = e1[e].next)
    		if(!dfn[e1[e].to]) Dfs2(e1[e].to, e1[e].to);
    }
    
    IL int LCA(RG int u, RG int v){
    	while(top[u] ^ top[v])
    		deep[top[u]] > deep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
    	return deep[u] > deep[v] ? v : u;
    }
    
    IL int Dis(RG int u, RG int v){
    	RG int lca = LCA(u, v);
    	return deep[u] + deep[v] - 2 * deep[lca];
    }
    
    IL int Cmp(RG int u, RG int v){
    	return dfn[u] < dfn[v];
    }
    
    IL void DP(RG int u){
    	g[u] = inf, f[u] = -inf;
    	if(num[u]) g[u] = f[u] = 0;
    	for(RG int e = first2[u]; e != -1; e = e2[e].next){
    		RG int v = e2[e].to, w = Dis(u, v);
    		DP(v), num[u] += num[v];
    		sum += (tot - num[v]) * num[v] * w;
    		mn = min(mn, g[u] + w + g[v]);
    		mx = max(mx, f[u] + w + f[v]);
    		g[u] = min(g[u], g[v] + w);
    		f[u] = max(f[u], f[v] + w);
    	}
    }
    
    int main(){
    	n = Input();
    	for(RG int i = 1; i <= n; ++i) first1[i] = first2[i] = -1;
    	for(RG int i = 1; i < n; ++i){
    		RG int u = Input(), v = Input();
    		Add1(u, v), Add1(v, u);
    	}
    	Dfs1(1), Dfs2(1, 1);
    	for(RG int q = Input(); q; --q){
    		RG int k = Input(); cnt = 0, tot = k;
    		for(RG int i = 1; i <= k; ++i) p[i] = Input(), num[p[i]] = 1;
    		sort(p + 1, p + k + 1, Cmp);
    		for(RG int i = 1, t = k; i < t; ++i) p[++k] = LCA(p[i], p[i + 1]);
    		sort(p + 1, p + k + 1, Cmp), k = unique(p + 1, p + k + 1) - p - 1;
    		for(RG int i = 1; i <= k; ++i) first2[p[i]] = -1;
    		RG int t = 0;
    		for(RG int i = 1; i <= k; ++i){
    			while(t && dfn[p[i]] >= dfn[s[t]] + size[s[t]]) --t;
    			if(t) Add2(s[t], p[i]);
    			s[++t] = p[i];
    		}
    		mx = sum = 0, mn = inf;
    		DP(p[1]);
    		printf("%lld %lld %lld
    ", sum, mn, mx);
    		for(RG int i = 1; i <= k; ++i) num[p[i]] = 0;
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    [转]Nvidia 的Shadow 文章收集
    [转]Linear Depth Buffer(线性深度缓冲区)
    [转]ParallelSplit Shadow Maps on Programmable GPUs
    [转]Learning to Love your Zbuffer.
    SQL SERVER存储过程中使用事务
    VS2005+SQL2005 Reporting Service动态绑定报表(Web)
    Sql批量删除/插入
    存储过程中执行动态Sql语句
    存储过程中使用事务
    真正的全动态报表:RDLC+ReportViewer
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/9113969.html
Copyright © 2020-2023  润新知