BZOJ3611 HEOI2014大工程
先建虚树,然后统计答案。
对于这个两点间最大值和最小值的操作我参考了hzwer的代码。
建虚树时注意判自环
By:大奕哥
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e6+10; 4 struct node{ 5 int to,nex,w; 6 }e[N<<1],d[N<<1]; 7 int cnt,dnt,dead[N],head[N],ans1,ans2,id,idx[N],h[N],f[N][21],dd[N],q,n,top,size[N]; 8 bool v[N];long long sum; 9 void add(int x,int y,int w) 10 { 11 e[++cnt].to=y;e[cnt].w=w;e[cnt].nex=head[x];head[x]=cnt; 12 } 13 void ddd(int x,int y,int w) 14 { 15 if(x==y)return; 16 d[++dnt].to=y;d[dnt].w=w;d[dnt].nex=dead[x];dead[x]=dnt; 17 } 18 void dfs(int x,int fa) 19 { 20 for(int i=1;i<=20;++i) 21 f[x][i]=f[f[x][i-1]][i-1]; 22 idx[x]=++id; 23 for(int i=head[x];i;i=e[i].nex) 24 { 25 int y=e[i].to; 26 if(y==fa)continue; 27 f[y][0]=x;dd[y]=dd[x]+1; 28 dfs(y,x); 29 } 30 } 31 int lca(int x,int y) 32 { 33 if(dd[x]<dd[y])swap(x,y); 34 int tmp=dd[x]-dd[y]; 35 for(int i=0;i<=20;++i) 36 if(tmp&(1<<i))x=f[x][i]; 37 for(int i=20;i>=0;--i) 38 if(f[x][i]!=f[y][i]) 39 x=f[x][i],y=f[y][i]; 40 return x==y?x:f[x][0]; 41 } 42 long long dp[N]; 43 int mx[N],mn[N],k,s[N]; 44 void donggui(int x) 45 { 46 size[x]=v[x];dp[x]=0; 47 mn[x]=v[x]?0:2e9; 48 mx[x]=v[x]?0:-2e9; 49 for(int i=dead[x];i;i=d[i].nex) 50 { 51 int y=d[i].to; 52 donggui(y); 53 sum+=1ll*(dp[x]+1ll*size[x]*d[i].w)*size[y]+1ll*dp[y]*size[x]; 54 size[x]+=size[y]; 55 dp[x]+=dp[y]+1ll*size[y]*d[i].w; 56 ans1=min(ans1,mn[x]+d[i].w+mn[y]); 57 ans2=max(ans2,mx[x]+d[i].w+mx[y]); 58 mn[x]=min(mn[x],mn[y]+d[i].w); 59 mx[x]=max(mx[x],mx[y]+d[i].w); 60 } 61 dead[x]=0; 62 } 63 bool cmp(int x,int y) 64 { 65 return idx[x]<idx[y]; 66 } 67 void solve() 68 { 69 scanf("%d",&k); 70 for(int i=1;i<=k;++i)scanf("%d",&h[i]); 71 for(int i=1;i<=k;++i)v[h[i]]=1; 72 sort(h+1,h+1+k,cmp); 73 top=dnt=0; 74 s[++top]=1; 75 for(int i=1;i<=k;++i) 76 { 77 int x=h[i];int ff=lca(x,s[top]); 78 if(ff==s[top]){s[++top]=x;continue;} 79 while(ff==lca(s[top-1],x)) 80 { 81 ddd(s[top-1],s[top],dd[s[top]]-dd[s[top-1]]); 82 top--;ff=lca(s[top],x); 83 } 84 ddd(ff,s[top],dd[s[top]]-dd[ff]); 85 s[top]=ff;s[++top]=x; 86 } 87 for(int i=1;i<top;++i) 88 ddd(s[i],s[i+1],dd[s[i+1]]-dd[s[i]]); 89 ans1=2e9;ans2=-2e9;sum=0; 90 donggui(1); 91 printf("%lld %d %d\n",sum,ans1,ans2); 92 for(int i=1;i<=k;++i)v[h[i]]=0; 93 return; 94 } 95 int main() 96 { 97 scanf("%d",&n); 98 for(int i=1;i<n;++i) 99 { 100 int x,y; 101 scanf("%d%d",&x,&y); 102 add(x,y,1);add(y,x,1); 103 } 104 dfs(1,0); 105 scanf("%d",&q); 106 while(q--)solve(); 107 return 0; 108 }
生命中真正重要的不是你遭遇了什么,而是你记住了哪些事,又是如何铭记的。