【题解】Luogu P3639 [APIO2013] 道路费用

\(k\le 20\),考虑 \(O(2^k)\) 暴力枚举加入的边。但是边数很大,时间复杂度很高无法承受。

考虑在一开始强制选这 \(k\) 条边,然后跑最小生成树,此时加入的边就是一定会加入的边。设这个边集为 \(S\)

\(S\) 连接的连通块缩成点,点数为 \(O(k)\)。再在原图上对这些点跑最小生成树,设加入的边集为 \(T\),则 \(T\) 为加入那 \(k\) 条边后有可能在最小生成树中的边。数量也为 \(O(k)\)

然后暴力枚举强制加入的边,用 \(T\) 跑出最小生成树,再用 \(T\) 中的非树边限制强制加入的边即可。具体地,对于一条非树边 \((u,v)\),树上 \(u\)\(v\) 的路径中的所有边都应该大于等于这条非树边的边权。暴力跳父亲即可。

考虑统计答案,只需要计算通过每条边的人数,用 dfs 计算子树权值和即可。

时间复杂度 \(O(m\log m+2^kk^2)\)

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
#include<bits/stdc++.h> #define int long long #define il inline #define pii pair<int,int> #define mp make_pair #define fir first #define sec second #define pb push_back using namespace std; namespace asbt{ namespace cplx{bool begin;} const int maxn=3e5+5; int n,m,k,a[maxn],bel[maxn]; bool vis[maxn]; vector<int> dk; vector<pii> e[maxn]; struct edge{ int u,v,w; il bool operator<(const edge &x)const{ return w<x.w; } }em[maxn],ek[maxn]; vector<edge> et; int fa[maxn],sz[maxn],ans; int mxe[maxn],dep[maxn],tof[maxn]; il void init(){ for(int i=1;i<=n;i++){ fa[i]=i,sz[i]=1; } } il int find(int x){ return x!=fa[x]?fa[x]=find(fa[x]):x; } il void merge(int u,int v){ u=find(u),v=find(v); if(u==v){ return ; } if(sz[u]>sz[v]){ sz[u]+=sz[v],fa[v]=u; } else{ sz[v]+=sz[u],fa[u]=v; } } il void dfs(int u){ dep[u]=dep[fa[u]]+1; sz[u]=a[u]; for(pii i:e[u]){ int v=i.fir,w=i.sec; if(v!=fa[u]){ fa[v]=u; tof[v]=w; dfs(v); sz[u]+=sz[v]; } } } il void solve(int S){ for(int u:dk){ fa[u]=u,sz[u]=1,e[u].clear(); } for(int i=1,u,v;i<=k;i++){ if(S>>(i-1)&1){ u=bel[ek[i].u],v=bel[ek[i].v]; if(find(u)==find(v)){ return ; } merge(u,v); e[u].pb(mp(v,-i)); e[v].pb(mp(u,-i)); } } for(int i=0;i<et.size();i++){ vis[i]=0; } for(int i=0,u,v,w;i<et.size();i++){ u=et[i].u,v=et[i].v,w=et[i].w; if(find(u)!=find(v)){ merge(u,v); vis[i]=1; e[u].pb(mp(v,w)); e[v].pb(mp(u,w)); } } for(int i=1;i<=k;i++){ mxe[i]=INT_MAX; } for(int u:dk){ dep[u]=tof[u]=fa[u]=sz[u]=0; } dfs(bel[1]); // puts("666"); for(int i=0,u,v,w;i<et.size();i++){ // cout<<i<<"\n"; if(vis[i]){ continue; } u=et[i].u,v=et[i].v,w=et[i].w; if(dep[u]<dep[v]){ swap(u,v); } // cout<<dep[u]<<" "<<dep[v]<<"\n"; while(dep[u]>dep[v]){ // puts("666"); if(tof[u]<0){ mxe[-tof[u]]=min(mxe[-tof[u]],w); } u=fa[u]; } while(u!=v){ if(tof[u]<0){ mxe[-tof[u]]=min(mxe[-tof[u]],w); } if(tof[v]<0){ mxe[-tof[v]]=min(mxe[-tof[v]],w); } u=fa[u],v=fa[v]; } } for(int u:dk){ if(tof[u]<0){ tof[u]=-mxe[-tof[u]]; } } int res=0; for(int u:dk){ if(tof[u]<0){ res-=tof[u]*sz[u]; } } ans=max(ans,res); } namespace cplx{ bool end; il double usdmem(){return (&begin-&end)/1048576.0;} } signed main(){ // cout<<cplx::usdmem(); ios::sync_with_stdio(0),cin.tie(0); // freopen("toll5.in","r",stdin); cin>>n>>m>>k; // cout<<n<<" "<<m<<" "<<k<<"\n"; for(int i=1;i<=m;i++){ cin>>em[i].u>>em[i].v>>em[i].w; } init(),sort(em+1,em+m+1); for(int i=1;i<=k;i++){ cin>>ek[i].u>>ek[i].v; merge(ek[i].u,ek[i].v); } for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=1,u,v;i<=m;i++){ u=em[i].u,v=em[i].v; if(find(u)!=find(v)){ merge(u,v); vis[i]=1; } } init(); for(int i=1,u,v;i<=m;i++){ if(vis[i]){ u=find(em[i].u); v=find(em[i].v); if(sz[u]>sz[v]){ sz[u]+=sz[v]; a[u]+=a[v]; fa[v]=u; } else{ sz[v]+=sz[u]; a[v]+=a[u]; fa[u]=v; } } } for(int i=1;i<=n;i++){ bel[i]=find(i); if(bel[i]==i){ dk.pb(i); } } init(); for(int i=1,u,v,w;i<=m;i++){ u=bel[em[i].u],v=bel[em[i].v],w=em[i].w; if(find(u)!=find(v)){ et.pb((edge){u,v,w}); merge(u,v); } } for(int S=0;S<1<<k;S++){ // cout<<bitset<15>(S)<<"\n"; solve(S); } cout<<ans; return 0; } } signed main(){return asbt::main();} /* 100000 299989 12 */
posted @   zhangxy__hp  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开