【题解】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
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
*/
分类:
题解类
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步