【题解】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)\)。
#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
*/

浙公网安备 33010602011771号