题解:虚树模板题 维护虚树 跑树dp即可
/**************************************************************
Problem: 3611
User: c20161007
Language: C++
Result: Accepted
Time:15176 ms
Memory:357336 kb
****************************************************************/
#include <bits/stdc++.h>
#define ll long long
const int MAXN=1e6+10;
using namespace std;
const ll inf=1e18;
vector<int>vec[MAXN];
int f[MAXN][21];ll sum[MAXN][21];int dep[MAXN];
int p[MAXN],cnt;
int st[MAXN],tot;
vector<int>V;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
void dfs(int v,int pre,int deep){
dep[v]=deep;f[v][0]=pre;p[v]=++cnt;
for(int i=0;i<vec[v].size();i++){
int u=vec[v][i];
if(u!=pre){
sum[u][0]=1;
dfs(u,v,deep+1);
}
}
}
void dfs1(int v){
for(int i=1;i<=20;i++)sum[v][i]=sum[f[v][i-1]][i-1]+sum[v][i-1],f[v][i]=f[f[v][i-1]][i-1];
for(int i=0;i<vec[v].size();i++){
int u=vec[v][i];
if(u!=f[v][0])dfs1(u);
}
}
int Lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
int tmp=dep[u]-dep[v];
for(int i=0;i<=20;i++)if(tmp&(1<<i))u=f[u][i];
if(u==v)return u;
for(int i=20;i>=0;i--){
if(f[u][i]!=f[v][i]){
u=f[u][i];
v=f[v][i];
}
}
return f[u][0];
}
void built(int x){
V.push_back(x);
if(!tot){st[++tot]=x;return ;}
int lca=Lca(x,st[tot]);
// cout<<lca<<" "<<x<<" "<<st[tot]<<endl;
while(tot>1&&dep[lca]<dep[st[tot-1]]){
vec[st[tot]].push_back(st[tot-1]);
vec[st[tot-1]].push_back(st[tot]);
tot--;
}
if(dep[st[tot]]>dep[lca]){
// cout<<lca<<"::::"<<st[tot]<<endl;
vec[st[tot]].push_back(lca);
vec[lca].push_back(st[tot]);
tot--;
V.push_back(lca);
}
// cout<<tot<<"====="<<endl;
if(!tot||dep[lca]>dep[st[tot]])st[++tot]=lca;
// cout<<st[tot]<<endl;
st[++tot]=x;
}
ll dist(int u,int v){
ll res=0;
// cout<<u<<"::::::"<<v<<endl;
for(int i=20;i>=0;i--){
if(dep[f[u][i]]>dep[v]){
res+=sum[u][i];
// cout<<u<<"::::"<<f[u][i]<<" "<<res<<endl;
u=f[u][i];
}
}
res+=sum[u][0];
return res;
}
ll _f[MAXN],__f[MAXN],d[MAXN],_d[MAXN];
int num[MAXN];
bool vis[MAXN];
ll ans;
int po;
void dfs(int x,int pre){
// cout<<x<<" "<<pre<<endl;
__f[x]=_d[x]=inf;_f[x]=d[x]=0;
if(vis[x])num[x]=1;
for(int i=0;i<vec[x].size();i++){
if(vec[x][i]!=pre){
dfs(vec[x][i],x);
num[x]+=num[vec[x][i]];
ll vul=dist(vec[x][i],x);
ans+=1ll*vul*num[vec[x][i]]*(po-num[vec[x][i]]);
if(d[vec[x][i]]||vis[vec[x][i]]){
_f[x]=max(_f[x],d[x]+d[vec[x][i]]+vul);
_f[x]=max(_f[x],_f[vec[x][i]]);
d[x]=max(d[x],d[vec[x][i]]+vul);
__f[x]=min(__f[x],__f[vec[x][i]]);
__f[x]=min(__f[x],_d[x]+_d[vec[x][i]]+vul);
_d[x]=min(_d[x],_d[vec[x][i]]+vul);
if(vis[x])_f[x]=max(_f[x],d[vec[x][i]]+vul),__f[x]=min(__f[x],_d[vec[x][i]]+vul);
}
}
}
if(vis[x])_d[x]=0;
if(!d[x])_d[x]=0;
}
int n,m;
bool cmp(int aa,int bb){return p[aa]<p[bb];}
int main(){
n=read();int u,v;
for(int i=1;i<n;i++)u=read(),v=read(),vec[u].push_back(v),vec[v].push_back(u);
// cout<<"sb"<<endl;
dfs(1,0,0);dfs1(1);int k;
for(int i=1;i<=n;i++)vec[i].clear();
m=read();
for(int i=1;i<=m;i++){
k=read();tot=0;ans=0;po=k;
for(int i=1;i<=k;i++)v=read(),V.push_back(v),vis[v]=1;
sort(V.begin(),V.end(),cmp);
for(int i=1;i<=k;i++)built(V[i-1]);
// for(int i=tot;i>=1;i--)cout<<st[i]<<" ";
// cout<<endl;
while(tot>1){vec[st[tot]].push_back(st[tot-1]),vec[st[tot-1]].push_back(st[tot]);tot--;}
// cout<<vec[1].size()<<" "<<vec[4].size()<<" "<<vec[5].size()<<endl;
// cout<<st[tot]<<endl;
dfs(st[tot],f[st[tot]][0]);
printf("%lld %lld %lld\n",ans,__f[st[tot]],_f[st[tot]]);
//V.clear();
for(int i=0;i<V.size();i++)vec[V[i]].clear(),vis[V[i]]=0,num[V[i]]=0;
V.clear();
}
return 0;
}
3611: [Heoi2014]大工程
Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 2194 Solved: 945
[Submit][Status][Discuss]
Description
国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。
我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。
在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径。
现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道。
现在对于每个计划,我们想知道:
1.这些新通道的代价和
2.这些新通道中代价最小的是多少
3.这些新通道中代价最大的是多少
Input
第一行 n 表示点数。
接下来 n-1 行,每行两个数 a,b 表示 a 和 b 之间有一条边。
点从 1 开始标号。 接下来一行 q 表示计划数。
对每个计划有 2 行,第一行 k 表示这个计划选中了几个点。
第二行用空格隔开的 k 个互不相同的数表示选了哪 k 个点。
Output
输出 q 行,每行三个数分别表示代价和,最小代价,最大代价。
Sample Input
10
2 1
3 2
4 1
5 2
6 4
7 5
8 6
9 7
10 9
5
2
5 4
2
10 4
2
5 2
2
6 1
2
6 1
2 1
3 2
4 1
5 2
6 4
7 5
8 6
9 7
10 9
5
2
5 4
2
10 4
2
5 2
2
6 1
2
6 1
Sample Output
3 3 3
6 6 6
1 1 1
2 2 2
2 2 2
6 6 6
1 1 1
2 2 2
2 2 2
HINT
n<=1000000
q<=50000并且保证所有k之和<=2*n