【TYVJ 五月图论专项有奖比赛】
最短路+TSP+最小生成树+倍增LCA+TreeDP
第一题
其实是个TSP问题(然而我没发现),但是关键点很少,只有5个,所以用dij+heap分别预处理出来这五个点为源的最短路……
然后枚举起点 i ,枚举这5个点的经过顺序,然后O(1)处理答案就可以了……
容易写错的地方是 五个点的标号(a[i]),以及第几个点(i),这个地方容易搞混……
我爆零的地方是:有个地方原来写的是 i 循环,然而我修改了以后内层变成 j 循环了,但是我没改循环内的语句……
还有就是数组应该开 len[M<<1]的,我开成len[N<<1] 了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<queue> 2 #include<vector> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 #define rep(i,n) for(int i=0;i<n;++i) 9 #define F(i,j,n) for(int i=j;i<=n;++i) 10 #define D(i,j,n) for(int i=j;i>=n;--i) 11 using namespace std; 12 13 int getint(){ 14 int v=0,sign=1; char ch=getchar(); 15 while(ch<'0'||ch>'9') {if (ch=='-') sign=-1; ch=getchar();} 16 while(ch>='0'&&ch<='9') {v=v*10+ch-'0'; ch=getchar();} 17 return v*sign; 18 } 19 typedef long long LL; 20 const int N=10010,M=50010,INF=~0u>>2; 21 /*******************template********************/ 22 int to[M<<1],next[M<<1],len[M<<1],head[N],cnt; 23 void add(int x,int y,int z){ 24 to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt; len[cnt]=z; 25 to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt; len[cnt]=z; 26 } 27 28 int n,m,k; 29 int a[10],b[10],d[10][N]; 30 bool vis[N],sign[N]; 31 struct node{int x,d;}; 32 bool operator < (node a,node b){return a.d>b.d;} 33 priority_queue<node>Q; 34 35 void dij(int s){ 36 memset(d[s],0x3f,sizeof d[s]); 37 memset(vis,0,sizeof vis); 38 d[s][a[s]]=0; 39 Q.push((node){a[s],0}); 40 while(!Q.empty()){ 41 int x=Q.top().x; Q.pop(); 42 if (vis[x]) continue; 43 vis[x]=1; 44 for(int i=head[x];i;i=next[i]) 45 if (d[s][to[i]]>d[s][x]+len[i]){ 46 d[s][to[i]]=d[s][x]+len[i]; 47 Q.push((node){to[i],d[s][to[i]]}); 48 } 49 } 50 } 51 int ans=1e9+10; 52 void check(){ 53 int tmp=0; 54 F(i,1,n){ 55 tmp=0; 56 if (!sign[i]){ 57 tmp+=d[b[1]][i]+d[b[k]][i]; 58 F(j,1,k-1) tmp+=d[b[j]][ a[b[j+1]] ]; 59 ans=min(ans,tmp); 60 } 61 } 62 } 63 bool chk[10]; 64 void dfs(int x){ 65 if (x==k+1) check(); 66 F(i,1,k) if (!chk[i]){ 67 b[x]=i; 68 chk[i]=1; 69 dfs(x+1); 70 b[x]=0; 71 chk[i]=0; 72 } 73 } 74 int main(){ 75 n=getint(); m=getint(); k=getint(); 76 F(i,1,k){ 77 a[i]=getint(); 78 sign[a[i]]=1; 79 } 80 F(i,1,m){ 81 int x=getint(),y=getint(),z=getint(); 82 add(x,y,z); 83 } 84 F(i,1,k) dij(i); 85 dfs(1); 86 printf("%d\n",ans); 87 return 0; 88 }
第二题
跟NOIP 2012的d1t3(希望没记错时间……那题叫货车运输……)几乎完全相同的题,只不过那题是找最小,这题是最大。
搞一个最大生成树,然后在树上倍增就可以了。
40分?……因为忘记判impossible了……2333
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<vector> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<iostream> 6 #include<algorithm> 7 #define rep(i,n) for(int i=0;i<n;++i) 8 #define F(i,j,n) for(int i=j;i<=n;++i) 9 #define D(i,j,n) for(int i=j;i>=n;--i) 10 using namespace std; 11 typedef long long LL; 12 inline int getint(){ 13 int r=1,v=0; char ch=getchar(); 14 for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; 15 for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; 16 return r*v; 17 } 18 const int N=1e5+10,M=3e5+10; 19 /*******************template********************/ 20 21 int to[N<<1],next[N<<1],head[N],len[N<<1],cnt; 22 void add(int x,int y,int z){ 23 to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt; len[cnt]=z; 24 to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt; len[cnt]=z; 25 } 26 struct edge{int u,v,w;}E[M]; 27 bool cmp(const edge &a,const edge &b){return a.w<b.w;} 28 int f[N],sz[N]; 29 inline int getf(int x){return f[x]==x ? x : getf(f[x]);} 30 31 int fa[N][20],mx[N][20],dep[N],n,m; 32 void dfs(int x){ 33 F(i,1,17) 34 if (dep[x]>=(1<<i)){ 35 fa[x][i]=fa[fa[x][i-1]][i-1]; 36 mx[x][i]=max(mx[fa[x][i-1]][i-1],mx[x][i-1]); 37 }else break; 38 for(int i=head[x];i;i=next[i]) 39 if (to[i]!=fa[x][0]){ 40 fa[to[i]][0]=x; 41 dep[to[i]]=dep[x]+1; 42 mx[to[i]][0]=len[i]; 43 dfs(to[i]); 44 } 45 } 46 int query(int x,int y){ 47 if (dep[x]<dep[y]) swap(x,y); 48 int t=dep[x]-dep[y]; 49 int ans=0; 50 F(i,0,17) if (t&(1<<i)){ 51 ans=max(mx[x][i],ans); 52 x=fa[x][i]; 53 } 54 D(i,17,0) if (fa[x][i]!=fa[y][i]){ 55 ans=max(mx[x][i],ans); 56 ans=max(mx[y][i],ans); 57 x=fa[x][i]; y=fa[y][i]; 58 } 59 if (x!=y) ans=max(ans,max(mx[x][0],mx[y][0])); 60 return ans; 61 } 62 int main(){ 63 n=getint(); m=getint(); 64 F(i,1,m){ 65 int x=getint(),y=getint(),z=getint(); 66 E[i]=(edge){x,y,z}; 67 } 68 sort(E+1,E+m+1,cmp); 69 F(i,1,n) f[i]=i,sz[i]=1; 70 F(i,1,m){ 71 int f1=getf(E[i].u),f2=getf(E[i].v); 72 if (f1!=f2){ 73 if (sz[f1]>sz[f2]) swap(f1,f2); 74 f[f1]=f2; 75 sz[f2]+=sz[f1]; 76 add(E[i].u,E[i].v,E[i].w); 77 } 78 } 79 80 dfs(1); 81 int T=getint(); 82 while(T--){ 83 int x=getint(),y=getint(); 84 if (getf(x)!=getf(y)) puts("impossible"); 85 else printf("%d\n",query(x,y)); 86 } 87 return 0; 88 }
第三题
我并不会写……只好预处理出来dist[i][j]数组,然后$N^2$枚举+O(n)判断……三次方的做法骗了30分= =
然而正解是找树的重心?预处理出来每棵子树的答案,由于整棵树分成的两部分是一棵完整的子树+剩下的部分,所以枚举那个砍掉的子树?在再加上一些神奇的技巧……
然而一上午也没yy出来果然代码能力就是渣渣,sad……
UPD:2015年5月20日 16:28:33
Orz zyf神犇
果然是……枚举断了哪条边,然后暴力修改= =用dfs整棵树来选边就可以,从当前点沿fa修改上去,两半树各求一遍答案……ok……无限ym啊……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //TYVJ C 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<iostream> 6 #include<algorithm> 7 #define rep(i,n) for(int i=0;i<n;++i) 8 #define F(i,j,n) for(int i=j;i<=n;++i) 9 #define D(i,j,n) for(int i=j;i>=n;--i) 10 #define pb push_back 11 using namespace std; 12 typedef long long LL; 13 inline int getint(){ 14 int r=1,v=0; char ch=getchar(); 15 for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; 16 for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; 17 return r*v; 18 } 19 const int N=100010; 20 /*******************template********************/ 21 int to[N<<1],next[N<<1],head[N],cnt; 22 void add(int x,int y){ 23 to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt; 24 to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt; 25 } 26 27 int n,a[N],f[N][2],dep[N],s[N],fa[N],cut; 28 LL g[N],ans=1e15; 29 void dfs(int x){ 30 for(int i=head[x];i;i=next[i]) 31 if (to[i]!=fa[x]){ 32 dep[to[i]]=dep[x]+1; 33 fa[to[i]]=x; 34 dfs(to[i]); 35 s[x]+=s[to[i]]; 36 if (s[to[i]]>s[f[x][0]]) f[x][1]=f[x][0],f[x][0]=to[i]; 37 else if (s[to[i]]>s[f[x][1]]) f[x][1]=to[i]; 38 g[x]+=g[to[i]]+s[to[i]]; 39 } 40 } 41 LL getans(int x,int cnt){ 42 int t=(f[x][0]==cut || s[f[x][1]]>s[f[x][0]]) ? f[x][1] : f[x][0]; 43 if (2*s[t]>cnt) return 2*s[t]-cnt+getans(t,cnt); 44 else return 0; 45 } 46 void dp(int x){ 47 for(int i=head[x];i;i=next[i]) 48 if (to[i]!=fa[x]){ 49 cut=to[i]; 50 for(int j=x;j;j=fa[j]) s[j]-=s[to[i]]; 51 ans=min(ans,g[1]-g[to[i]]-(LL)s[to[i]]*dep[to[i]]-getans(1,s[1])+g[to[i]]-getans(to[i],s[to[i]])); 52 for(int j=x;j;j=fa[j]) s[j]+=s[to[i]]; 53 dp(to[i]); 54 } 55 } 56 57 int main(){ 58 #ifndef ONLINE_JUDGE 59 freopen("C.in","r",stdin); 60 freopen("C.out","w",stdout); 61 #endif 62 n=getint(); 63 F(i,2,n){ 64 int x=getint(),y=getint(); 65 add(x,y); 66 } 67 F(i,1,n) s[i]=getint(); 68 dfs(1); 69 dp(1); 70 printf("%lld\n",ans); 71 return 0; 72 }