CF1508C tj
CF1508C
你总不能一下午啥事情都没干吧。
题面
作为一名教师,Riko Hakozaki 经常需要帮助她的学生解决各类学科的问题。今天,她被问到了一个编程任务,内容如下:
给定一个无向完全图,包含 \(n\) 个节点,其中部分边已经被赋予了正权值,其余边尚未赋值。你需要为所有未赋值的边分配非负权值,使得最终所有边都被赋值后的完全图中,所有边权的异或和等于 \(0\)。
定义一个完全赋值的完全图的“丑陋度”为其最小生成树的权值,即最小生成树所有边权之和。你需要合理分配权值,使得最终图的丑陋度尽可能小。
提示:一个无向完全图有 \(n\) 个节点,包含所有 \(1 \le u < v \le n\) 的边;这样的图共有 \(\frac{n(n-1)}{2}\) 条边。
她不确定如何解决这个问题,因此请你帮她解决。
sol
又是分讨题。
设原来边权的异或值为 \(S\)。
发现如果我们想要让这个最小生成树尽量小的话,有一个简单的做法是只定一条边为 \(S\),剩下全填 \(0\),感性理解一下会发现这个是对的。
在未赋值的边联通且有环的情况下答案一定为 \(0\)。
接下来就有两种情况需要讨论了:
补图刚好是一棵树。
这种情况点数不会太多,暴力枚举哪条边改为 \(S\) 跑最小生成树就行了。
直接做就是 \(O(n^3\log n^2)\) 的。
补图不连通
这个时候也得分两种情况,看有没有环。
有环我直接把补图连通块跑出来搞最小生成树就行了,那个边权为 \(S\) 的边随便找个环放了就好了。
没环的时候也可以说明点数不会太多,也是枚举哪条边放就完事了,也是 \(O(n^3\log n^2)\)。
代码还没写,但是这个能难写到哪去???
实现需要精细实现 (有点搞人)。
比如算补图为森林/树的最小生成树需要通过先排序把他的边数降成 \(O(n)\) 的再跑。
以及算补图连通块,你先找到度数最小的一个点,那么这个连通块至少包含 \(n-m/n\) 个点,然后剩下的 \(m/n\) 暴力算就行了,均摊是 \(O(n)\) 的复杂度。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,m,chs[200001],v[200001],fa[200001],vis[701][701],vv[200001],viv[200001],tot,pnt,vl;
string s;
struct dcz{
int x,y,z;
}a[200001],b[400001],c[400001],d[400001];
bool cmp(dcz x,dcz y){
return x.z<y.z;
}
int gf(int x){
if(x==fa[x]) return x;
return fa[x]=gf(fa[x]);
}
struct sbdcz{
int nex,to;
}e[400001];
int cnt,head[200001],du[200001];
void add(int x,int y){
e[++cnt].nex=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void solve2(){//21í?2?á?í¨óD?·?£
// cout<<"?\n";
for(int i=1;i<=m;i++){
du[a[i].x]++,du[a[i].y]++;
add(a[i].x,a[i].y);
add(a[i].y,a[i].x);
}
int id=1;
for(int i=1;i<=n;i++){
fa[i]=i;
if(du[id]>du[i]) id=i;
}
for(int i=head[id];i;i=e[i].nex){
int v=e[i].to;
vv[v]=1;
}
for(int i=1;i<=n;i++){
if(!vv[i]) fa[i]=id;
}
for(int u=1;u<=n;u++){
if(!vv[u]||u==id) continue;
for(int i=1;i<=n;i++){
viv[i]=0;
}
for(int i=head[u];i;i=e[i].nex){
int v=e[i].to;
viv[v]=1;
}
int fu=gf(u);
for(int i=1;i<=n;i++){
if(!viv[i]){
int fx=gf(i);
fa[fx]=fu;
}
}
}
sort(a+1,a+m+1,cmp);
int ans=0;
for(int i=1;i<=m;i++){
int fx=gf(a[i].x),fy=gf(a[i].y);
if(fx!=fy){
ans+=a[i].z;
fa[fy]=fx;
}
}
cout<<ans<<"\n";
}
void solve1(){
sort(a+1,a+m+1,cmp);
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
vis[a[i].x][a[i].y]=1;
int fx=gf(a[i].x),fy=gf(a[i].y);
if(fx!=fy){
fa[fy]=fx;
d[++tot]=a[i];
}
}
for(int i=1;i<=n;i++){
fa[i]=i;
}
bool ff=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(vis[i][j]||vis[j][i]) continue;
int fx=gf(i),fy=gf(j);
if(fx==fy){ff=1;continue;}
fa[fy]=fx;
b[++pnt]={i,j,0};
}
}
int af=gf(1);bool f=1;
for(int i=1;i<=n;i++){
if(gf(i)!=af){f=0;break;}
}
if(f&&ff){ cout<<0<<"\n";return;}
else if(!ff){
int ans=LLONG_MAX;
for(int i=1;i<=pnt;i++){
b[i].z=vl;
for(int j=1;j<=n;j++){
fa[j]=j;
}
for(int j=1;j<=tot+pnt;j++){
if(j<=tot) c[j]=d[j];
else c[j]=b[j-tot];
// cout<<c[j].x<<' '<<c[j].y<<' '<<c[j].z<<"\n";
}
sort(c+1,c+tot+pnt+1,cmp);
int val=0,pnp=0;
for(int j=1;j<=tot+pnt;j++){
int fx=gf(c[j].x),fy=gf(c[j].y);
if(fx!=fy){
val+=c[j].z;pnp++;fa[fy]=fx;
if(pnp==n-1) break;
}
}
// cout<<val<<"\n";
ans=min(ans,val);
b[i].z=0;
}
cout<<ans<<"\n";return;
}
else solve2();
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>a[i].x>>a[i].y>>a[i].z;
vl^=a[i].z;
}
if(n<=700) solve1();
else solve2();
return 0;
}

浙公网安备 33010602011771号