Submit: 1281 Solved: 557
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
Source
树 虚树 树形DP
这次由于要统计每个点之间的信息,所以不能像2286那样偷懒少连子树的关键点了。
把每个关键点建到虚树上,然后跑树规
转移方程见代码。
自己写的方程各种乱还WAWAWA,于是拜读了黄学长的题解。(读书人的事……)
AC以后一看时间,10000+ms。
咋回事儿啊这么慢(懵X脸)
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 #define LL long long 9 using namespace std; 10 const int INF=0x3f3f3f3f; 11 const int mxn=1000010; 12 int read(){ 13 int x=0,f=1;char ch=getchar(); 14 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 15 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 16 return x*f; 17 } 18 struct edge{ 19 int v,nxt,w; 20 }e[mxn<<1],eg[mxn<<1]; 21 int hd[mxn],hd2[mxn],mct=0; 22 void add_edge(int u,int v){ 23 e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return; 24 } 25 int dep[mxn]; 26 void add(int u,int v){ 27 if(u==v)return; 28 eg[++mct].v=v;eg[mct].w=dep[v]-dep[u];eg[mct].nxt=hd2[u];hd2[u]=mct; 29 return; 30 } 31 //int dis[mxn]; 32 int fa[mxn][21]; 33 int ind[mxn],out[mxn],dtime=0; 34 void DFS(int u,int ff){ 35 dep[u]=dep[ff]+1; 36 ind[u]=++dtime; 37 for(int i=1;i<=20;i++)fa[u][i]=fa[fa[u][i-1]][i-1]; 38 for(int i=hd[u],v;i;i=e[i].nxt){ 39 if(e[i].v==ff)continue; 40 v=e[i].v; 41 fa[v][0]=u; 42 // dis[v]=dis[u]+1; 43 DFS(v,u); 44 } 45 out[u]=dtime; 46 return; 47 } 48 int LCA(int x,int y){ 49 if(dep[x]<dep[y])swap(x,y); 50 for(int i=20;i>=0;i--) 51 if(dep[fa[x][i]]>=dep[y])x=fa[x][i]; 52 if(x==y)return y; 53 for(int i=20;i>=0;i--){ 54 if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; 55 } 56 return fa[x][0]; 57 } 58 int fmi[mxn],fmx[mxn],sz[mxn]; 59 LL f[mxn],smm; 60 int ansmin,ansmax; 61 bool inq[mxn]; 62 void DP(int u){ 63 sz[u]=inq[u]; 64 f[u]=0; 65 fmi[u]=inq[u]?0:INF; 66 fmx[u]=inq[u]?0:-INF; 67 // printf("u:%d %d %d ",u,fmi[u],fmx[u]); 68 for(int i=hd2[u],v;i;i=eg[i].nxt){ 69 v=eg[i].v; 70 DP(v); 71 smm+=(f[u]+sz[u]*eg[i].w)*(LL)sz[v]+f[v]*sz[u];// 72 sz[u]+=sz[v]; 73 f[u]+=f[v]+eg[i].w*sz[v]; 74 ansmin=min(ansmin,fmi[u]+fmi[v]+eg[i].w); 75 ansmax=max(ansmax,fmx[u]+fmx[v]+eg[i].w); 76 fmi[u]=min(fmi[v]+eg[i].w,fmi[u]); 77 fmx[u]=max(fmx[v]+eg[i].w,fmx[u]); 78 } 79 hd2[u]=0; 80 return; 81 } 82 int a[mxn],st[mxn],top=0; 83 int cmp(int a,int b){return ind[a]<ind[b];} 84 void solve(){ 85 mct=0; 86 int i,j,K=read(); 87 for(i=1;i<=K;i++){a[i]=read();} 88 sort(a+1,a+K+1,cmp); 89 st[top=1]=1; 90 for(i=1;i<=K;i++)inq[a[i]]=1; 91 for(i=1;i<=K;i++){ 92 int now=a[i],tmp=LCA(a[i],st[top]); 93 if(tmp==st[top]){st[++top]=a[i];continue;} 94 while(1){ 95 if(dep[tmp]>=dep[st[top-1]]){ 96 add(tmp,st[top--]); 97 if(st[top]!=tmp)st[++top]=tmp; 98 break; 99 } 100 add(st[top-1],st[top]);top--; 101 } 102 if(st[top]!=now)st[++top]=now; 103 } 104 while(--top)add(st[top],st[top+1]); 105 smm=0;ansmin=INF;ansmax=-INF; 106 DP(1); 107 for(i=1;i<=K;i++)inq[a[i]]=0; 108 printf("%lld %d %d ",smm,ansmin,ansmax); 109 return; 110 } 111 int n,q; 112 int main(){ 113 int i,j,u,v; 114 n=read(); 115 for(i=1;i<n;i++){ 116 u=read();v=read(); 117 add_edge(u,v); 118 add_edge(v,u); 119 } 120 DFS(1,0); 121 q=read(); 122 while(q--)solve(); 123 return 0; 124 }
看到有人写树剖,那我也来个树剖LCA吧
于是跑到了3808ms,挤到了status第二页。
树剖真神奇
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 #define LL long long 9 using namespace std; 10 const int INF=0x3f3f3f3f; 11 const int mxn=1000010; 12 int read(){ 13 int x=0,f=1;char ch=getchar(); 14 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 15 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 16 return x*f; 17 } 18 struct edge{ 19 int v,nxt,w; 20 }e[mxn<<1],eg[mxn<<1]; 21 int hd[mxn],hd2[mxn],mct=0; 22 void add_edge(int u,int v){ 23 e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return; 24 } 25 int dep[mxn]; 26 void add(int u,int v){ 27 if(u==v)return; 28 eg[++mct].v=v;eg[mct].w=dep[v]-dep[u];eg[mct].nxt=hd2[u];hd2[u]=mct; 29 return; 30 } 31 // 32 int ind[mxn],out[mxn],dtime=0; 33 struct node{ 34 int fa,top,son; 35 int sz; 36 }t[mxn]; 37 void DFS(int u,int ff){ 38 dep[u]=dep[ff]+1; 39 t[u].sz++; 40 for(int i=hd[u],v;i;i=e[i].nxt){ 41 if(e[i].v==ff)continue; 42 v=e[i].v; 43 t[v].fa=u; 44 DFS(v,u); 45 t[u].sz+=t[v].sz; 46 if(t[v].sz>t[t[u].son].sz) 47 t[u].son=v; 48 } 49 50 return; 51 } 52 void DFS2(int u,int top){ 53 ind[u]=++dtime; 54 t[u].top=top; 55 if(t[u].son){ 56 DFS2(t[u].son,top); 57 for(int i=hd[u];i;i=e[i].nxt){ 58 if(e[i].v==t[u].son || e[i].v==t[u].fa)continue; 59 DFS2(e[i].v,e[i].v); 60 } 61 } 62 out[u]=dtime; 63 return; 64 } 65 int LCA(int x,int y){ 66 while(t[x].top!=t[y].top){ 67 if(dep[t[x].top]<dep[t[y].top])swap(x,y); 68 x=t[t[x].top].fa; 69 } 70 return dep[x]<dep[y]?x:y; 71 } 72 // 73 int fmi[mxn],fmx[mxn],sz[mxn]; 74 LL f[mxn],smm; 75 int ansmin,ansmax; 76 bool inq[mxn];//标记关键点 77 void DP(int u){ 78 sz[u]=inq[u]; 79 f[u]=0; 80 fmi[u]=inq[u]?0:INF; 81 fmx[u]=inq[u]?0:-INF; 82 for(int i=hd2[u],v;i;i=eg[i].nxt){ 83 v=eg[i].v; 84 DP(v); 85 smm+=(f[u]+sz[u]*eg[i].w)*(LL)sz[v]+f[v]*sz[u];// 86 sz[u]+=sz[v]; 87 f[u]+=f[v]+eg[i].w*sz[v]; 88 ansmin=min(ansmin,fmi[u]+fmi[v]+eg[i].w); 89 ansmax=max(ansmax,fmx[u]+fmx[v]+eg[i].w); 90 fmi[u]=min(fmi[v]+eg[i].w,fmi[u]); 91 fmx[u]=max(fmx[v]+eg[i].w,fmx[u]); 92 } 93 hd2[u]=0; 94 return; 95 } 96 int a[mxn],st[mxn],top=0; 97 int cmp(int a,int b){return ind[a]<ind[b];} 98 void solve(){ 99 mct=0; 100 int i,j,K=read(); 101 for(i=1;i<=K;i++){a[i]=read();} 102 sort(a+1,a+K+1,cmp); 103 st[top=1]=1; 104 for(i=1;i<=K;i++)inq[a[i]]=1; 105 for(i=1;i<=K;i++){ 106 int now=a[i],tmp=LCA(a[i],st[top]); 107 if(tmp==st[top]){st[++top]=a[i];continue;} 108 while(1){ 109 if(dep[tmp]>=dep[st[top-1]]){ 110 add(tmp,st[top--]); 111 if(st[top]!=tmp)st[++top]=tmp; 112 break; 113 } 114 add(st[top-1],st[top]);top--; 115 } 116 if(st[top]!=now)st[++top]=now; 117 } 118 while(--top)add(st[top],st[top+1]); 119 smm=0;ansmin=INF;ansmax=-INF; 120 DP(1); 121 for(i=1;i<=K;i++)inq[a[i]]=0; 122 printf("%lld %d %d ",smm,ansmin,ansmax); 123 return; 124 } 125 int n,q; 126 int main(){ 127 int i,j,u,v; 128 n=read(); 129 for(i=1;i<n;i++){ 130 u=read();v=read(); 131 add_edge(u,v); 132 add_edge(v,u); 133 } 134 DFS(1,0); 135 DFS2(1,1); 136 q=read(); 137 while(q--)solve(); 138 return 0; 139 }