HT-65-NOI-T2 / LOJ566 题解
Upd(26.06.19):三轮省集出这题,找到原题了。暴力调不过,发现去年写的暴力也挂了,原因是权值相等的边应该看成不等权值,即排序后对每个分界点做一遍。已更新。
题意
设一棵树的权值为
题解
显然给定
此时需要解决两种边分别选择
考虑用斜率为
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e5+10;
const int P=2e9+1e7;
const ll inf=1e18+1e17;
int n,m,cc,C,cnt,f[N],s[N]; ll res,cur;
struct edg{int u,v; ll w; bool f;}e[N],E[N];
int finds(int x) {return f[x]==x?x:f[x]=finds(f[x]);}
bool mg(int x,int y)
{
x=finds(x),y=finds(y);
if(x==y) return false;
if(s[x]>s[y]) swap(x,y);
f[x]=y,s[y]+=s[x]; return true;
}
void chk(ll k)
{
for(int i=1;i<=m;i++) E[i]=e[i],E[i].w-=E[i].f*k;
sort(E+1,E+1+m,[&](edg A,edg B)->bool {return A.w==B.w?A.f<B.f:A.w>B.w;});
for(int i=1;i<=n;i++) f[i]=i,s[i]=1;
cur=cnt=cc=0;
if(C) for(int i=1;i<=m;i++) if(mg(E[i].u,E[i].v))
{
cur+=E[i].w,cnt+=E[i].f,cc++;
if(cc==C*2) break;
}
}
ll calc(ll X)
{
cnt=0;
for(int i=1;i<=m;i++) e[i].w=(e[i].f?X-e[i].w:e[i].w-X);
ll l=-P,r=P,rk=P+1,tr;
while(l<=r)
{
ll mid=(l+r)/2; chk(mid);
if(cnt<=C) rk=mid,r=mid-1;
else l=mid+1;
}
chk(rk-1);
if(rk>P||cnt<C) tr=-inf;
else chk(rk),tr=cur+1ll*C*rk;
for(int i=1;i<=m;i++) e[i].w=(e[i].f?X-e[i].w:e[i].w+X);
return tr;
}
void sol()
{
cin>>n>>m,res=-inf,C=(n-1)/2;
for(int i=1;i<=m;i++) cin>>e[i].u>>e[i].v>>e[i].w,e[i].f=0;
sort(e+1,e+1+m,[&](edg A,edg B)->bool {return A.w<B.w;});
if(m>1000) return;
for(int i=1;i<=m;i++) e[i].f=1,res=max(res,calc(e[i].w));
cout<<res<<'\n';
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int TT=1;
while(TT--) sol();
return 0;
}
观察上述代码,注意到同时给所有边加上一个值
此时要求的问题如下:原图中每条边产生白边
此时显然存在一个
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N=5e5+10;
const int P=1e9+1e7;
const ll inf=1e18+1e17;
int n,m,k,c,a[N],f[N],s[N],C,cx; ll res,ans=-inf;
struct edg{int u,v,w;}e[N],E[N];
bool cmp(edg ta,edg tb) {return ta.w>tb.w;}
int finds(int x) {return f[x]==x?x:f[x]=finds(f[x]);}
bool merg(int x,int y)
{
x=finds(x),y=finds(y);
if(x==y) return false;
s[y]+=s[x],f[x]=y; return true;
}
void add(edg te,bool f)
{
if(C==c*2) return;
if(merg(te.u,te.v)) C++,cx+=f,res+=te.w;
}
void chk(ll X)
{
for(int i=1;i<=m;i++) e[i]=E[m-i+1],e[i].w=X-e[i].w;
res=0,C=0,cx=0; int pa=1,pb=1;
for(int i=1;i<=n;i++) f[i]=i,s[i]=1;
while(pa<=m&&pb<=m)
{
if(e[pa].w>E[pb].w) add(e[pa],1),pa++;
else add(E[pb],0),pb++;
}
while(pa<=m) add(e[pa],1),pa++;
while(pb<=m) add(E[pb],0),pb++;
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m,c=((n-1)>>1);
for(int i=1;i<=m;i++) cin>>E[i].u>>E[i].v>>E[i].w;
sort(E+1,E+1+m,cmp);
ll l=-P,r=2*P,rk=-P-1;
while(l<=r)
{
ll mid=((l+r)>>1); chk(mid);
if(cx<=c) rk=mid,l=mid+1;
else r=mid-1;
}
chk(rk),cout<<res-c*rk;
return 0;
}