[bzoj3611][Heoi2014]大工程
看题目感觉应该就是传说中的虚树?
然后跑去学了一发。。。自己YY了一下然后挂飞。。于是就只好抄模板了T_T
建完虚树就是个树形dp。。。
对于询问总和:每条边对答案的贡献是边权*一端的节点数*另一端的节点数。(这里的节点不包括建虚树时添上去的点)
对于询问最小值最大值,每次计算出经过这个节点的最长||最短路径长度就好了。。
大概这种题条件都有一个sigma(K)<=n之类的。。而且题目求的东西得符合区间加法。。。不然你把边合在一起也没用>_<
链剖求lca果然快。。。速度能进前10.。。然而代码长度实在感人= =
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define ll long long 6 using namespace std; 7 const int maxn=1000023; 8 const int inf=1002333333; 9 struct zs{ 10 int too,pre; 11 }e[maxn<<1]; 12 struct zs1{ 13 int too,pre,dis; 14 }e1[maxn<<2]; 15 int tot,tot1,last[maxn],last1[maxn]; 16 int sz[maxn],mn[maxn],mx[maxn]; 17 int intree[maxn],poi[maxn],rt; 18 int dfn[maxn],bel[maxn],size[maxn],dep[maxn],fa[maxn],tim; 19 int st[maxn],top; 20 int ansmn,ansmx; 21 ll anssum; 22 int i,j,k,n,m,K,a,b,lca; 23 24 25 int ra;char rx; 26 inline int read(){ 27 rx=getchar(),ra=0; 28 while(rx<'0'||rx>'9')rx=getchar(); 29 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 30 } 31 32 33 inline void insert(int a,int b){ 34 e[++tot].too=b,e[tot].pre=last[a],last[a]=tot; 35 e[++tot].too=a,e[tot].pre=last[b],last[b]=tot; 36 } 37 inline void ins(int a,int b){ 38 // printf(" %d-->%d\n",a,b); 39 e1[++tot1].too=b,e1[tot1].dis=dep[b]-dep[a],e1[tot1].pre=last1[a],last1[a]=tot1; 40 } 41 42 43 void dfs1(int x){ 44 size[x]=1; 45 for(int i=last[x];i;i=e[i].pre) 46 if(e[i].too!=fa[x]) 47 fa[e[i].too]=x, 48 dfs1(e[i].too), 49 size[x]+=size[e[i].too]; 50 } 51 void dfs2(int x,int chain){ 52 bel[x]=chain,dfn[x]=++tim,dep[x]=dep[fa[x]]+1;int mxpos=0,i,to; 53 for(to=e[i=last[x]].too;i;to=e[i=e[i].pre].too) 54 if(to!=fa[x]&&size[to]>size[mxpos])mxpos=to; 55 if(!mxpos)return; 56 dfs2(mxpos,chain); 57 for(to=e[i=last[x]].too;i;to=e[i=e[i].pre].too) 58 if(to!=fa[x]&&to!=mxpos)dfs2(to,to); 59 } 60 inline int getlca(int a,int b){ 61 if(dep[bel[a]]<dep[bel[b]])swap(a,b); 62 while(bel[a]!=bel[b]){ 63 a=fa[bel[a]]; 64 if(dep[bel[a]]<dep[bel[b]])swap(a,b); 65 } 66 return dep[a]<dep[b]?a:b; 67 } 68 69 70 bool cmp(int a,int b){return dfn[a]<dfn[b];} 71 72 inline int min(int a,int b){return a<b?a:b;} 73 inline int max(int a,int b){return a>b?a:b;} 74 void dp(int x){ 75 register int i,to; 76 if(intree[x]==m)sz[x]=1,mn[x]=mx[x]=0; 77 else sz[x]=0,mn[x]=inf,mx[x]=-inf; 78 for(to=e1[i=last1[x]].too;i;to=e1[i=e1[i].pre].too){ 79 dp(to),sz[x]+=sz[to],mn[to]+=e1[i].dis,mx[to]+=e1[i].dis; 80 anssum+=(ll)sz[to]*(K-sz[to])*e1[i].dis; 81 if(mn[x]+mn[to]<ansmn)ansmn=mn[x]+mn[to]; 82 if(mx[to]+mx[x]>ansmx)ansmx=mx[x]+mx[to]; 83 if(mn[to]<mn[x])mn[x]=mn[to];if(mx[to]>mx[x])mx[x]=mx[to]; 84 } 85 last1[x]=0; 86 } 87 88 89 char s[23];int len; 90 inline void outll(ll x){ 91 if(!x){putchar('0');return;} 92 for(len=0;x;s[++len]=x%10,x/=10); 93 while(len)putchar(s[len--]+48); 94 } 95 inline void outint(int x){ 96 if(!x){putchar('0');return;} 97 for(len=0;x;s[++len]=x%10,x/=10); 98 while(len)putchar(s[len--]+48); 99 } 100 101 102 int main(){ 103 register int i; 104 n=read(); 105 for(i=1;i<n;i++)a=read(),b=read(),insert(a,b); 106 dfs1(1),dfs2(1,1); 107 // for(i=1;i<=n;i++)printf(" %d %d\n",dep[i],dfn[i]); 108 // for(i=1;i<n;i++)for(j=i+1;j<=n;j++)printf(" %d&&%d %d\n",i,j,getlca(i,j)); 109 for(m=read();m;m--){ 110 tot1=0; 111 for(K=read(),i=1;i<=K;i++)intree[poi[i]=read()]=m; 112 sort(poi+1,poi+1+K,cmp);top=1,st[1]=poi[1]; 113 // for(i=1;i<=K;i++)printf(" %d\n",poi[i]); 114 for(i=2;i<=K;i++){ 115 lca=getlca(poi[i],st[top]); 116 while(dfn[lca]<dfn[st[top]]&&top) 117 if(dfn[st[top-1]]<=dfn[lca]){ 118 ins(lca,st[top--]); 119 if(st[top]!=lca)st[++top]=lca; 120 }else ins(st[top-1],st[top]),top--; 121 st[++top]=poi[i]; 122 } 123 while(top>1)ins(st[top-1],st[top]),top--; 124 ansmn=inf,ansmx=anssum=0,rt=st[1], 125 dp(rt); 126 outll(anssum),putchar(' '),outint(ansmn),putchar(' '),outint(ansmx),putchar('\n'); 127 } 128 return 0; 129 }