[ 虚树 ] [ Heoi2014 ] BZOJ3611 大工程

虚树裸题

#include<bits/stdc++.h>
using namespace std;
char nc() {
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
void Read(int& x) {
    char c=nc();
    for(;c<'0'||c>'9';c=nc());
    for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
typedef long long ll;
const int N=1000010;
const int INF=1e9;
const int M=21;
int k,n,m,x,y,Q,cnt,cur,tot;
int l[N],r[N],f[N][M],d[N];
int nx[N<<1],t[N<<1],w[N<<1],h[N],num;
int a[N<<1],top,Rt,st[N];
int sz[N],mx[N],mn[N];
int Ans1,Ans2;
ll Ans;
int v[N];
void Add(int x,int y) {
    t[++num]=y;nx[num]=h[x];h[x]=num;
}
void add(int x,int y,int z) {
    t[++num]=y;w[num]=z;nx[num]=h[x];h[x]=num;
}
void Dfs(int x,int y) {
    f[x][0]=y;d[x]=d[y]+1;l[x]=++cnt;
    for(int i=1;i<M;i++)
        f[x][i]=f[f[x][i-1]][i-1];
    for(int i=h[x];i;i=nx[i])
        if(t[i]!=y) Dfs(t[i],x);
    r[x]=cnt;
}
int Lca(int x,int y) {
    if(d[x]<d[y]) swap(x,y);
    for(int i=M-1;~i;i--) 
        if(d[f[x][i]]>=d[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=M-1;~i;i--)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
bool Cmp(int x,int y) {
    return l[x]<l[y];
}
bool Check(int x,int y) {
    return l[x]<=l[y]&&r[x]>=l[y];
}
void DP(int x,int y) {
    mx[x]=0;
    if(v[x]==cur) sz[x]=1,mn[x]=0;else sz[x]=0,mn[x]=INF;
    int mn1=INF,mx1=0;
    for(int i=h[x];i;i=nx[i]) 
        if(t[i]!=y) {
            DP(t[i],x);
            sz[x]+=sz[t[i]];
            Ans+=1ll*sz[t[i]]*(tot-sz[t[i]])*w[i];
            int tmp=mn[t[i]]+w[i];
            if(tmp<mn[x]) mn1=mn[x],mn[x]=tmp; else mn1=min(mn1,tmp);
            tmp=mx[t[i]]+w[i];
            if(tmp>mx[x]) mx1=mx[x],mx[x]=tmp; else mx1=max(mx1,tmp);
        }
    Ans1=min(Ans1,mn[x]+mn1);Ans2=max(Ans2,mx[x]+mx1);
}
void Solve() {
    sort(a+1,a+m+1,Cmp);
    ++cur;
    for(int i=1;i<=m;i++) v[a[i]]=cur;
    int t=m;
    for(int i=2;i<=m;i++) a[++t]=Lca(a[i-1],a[i]);
    sort(a+1,a+t+1,Cmp);
    m=unique(a+1,a+t+1)-a-1;top=num=0;
    for(int i=1;i<=m;i++) {
        int x=a[i];
        h[x]=0;
        while(top&&!Check(st[top],x)) --top;
        if(!top) Rt=x;else add(st[top],x,d[x]-d[st[top]]),add(x,st[top],d[x]-d[st[top]]);
        st[++top]=x;
    }
    Ans=0;Ans1=INF;Ans2=0;
    DP(Rt,0);
    printf("%lld %d %d\n",Ans,Ans1,Ans2);
}
int main() {
    Read(n);
    for(int i=1;i<n;i++) Read(x),Read(y),Add(x,y),Add(y,x);
    Dfs(1,0);
    Read(Q);
    while(Q--) {
        Read(m);tot=m;
        for(int i=1;i<=m;i++) Read(a[i]);
        Solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值