BZOJ2001: [Hnoi2010]City 城市建设

时间:2023-03-09 00:41:40
BZOJ2001: [Hnoi2010]City 城市建设

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2001

cdq分治+重建图。

可以保留当前一定会被选的非修改边然后把点缩起来。这样的话每次点数至多只有r-l+1个,边数只有2*(r-l+1)-1个(生成树+修改边)。

时间复杂度O(nlog^2(n))

#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 50050
#define ll long long
#define inf 1000000000
using namespace std;
struct data{int x,y;ll z;int k,id;
}a[][maxn];
struct node{int k;ll w;int id;
}b[maxn];
int fa[maxn],pos[maxn],p[maxn],n,m,Q;
ll dis[maxn];
int read(){
int x=,f=; char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-; ch=getchar();}
while (isdigit(ch)) {x=x*+ch-''; ch=getchar();}
return x*f;
}
int find(int x){
if (fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
bool cmp(data a,data b){
return a.z<b.z;
}
void cdq(int dep,int l,int r,int n,int m,ll ans){
rep(i,,m){
data &c=a[dep][i],&c2=a[dep-][i];
a[dep][i]=(data){c2.x,c2.y,dis[c2.id],,c2.id};
pos[c.id]=i;
}
//当l=r,计算答案,直接赋值当前修改边。
if (l==r){
data &c=a[dep][pos[b[l].k]]; c.z=dis[c.id]=b[l].w;
rep(i,,n) fa[i]=i;
sort(a[dep]+,a[dep]++m,cmp);
rep(i,,m){
int x=find(a[dep][i].x),y=find(a[dep][i].y);
if (x!=y) fa[x]=y,ans+=a[dep][i].z;
}
printf("%lld\n",ans);
return;
}
//删边,如果k=0,那么这是一条无用的边。
rep(i,l,r) a[dep][pos[b[i].k]].k=;
rep(i,,n) fa[i]=i;
sort(a[dep]+,a[dep]++m,cmp);
rep(i,,m) if (a[dep][i].k==){
int x=find(a[dep][i].x),y=find(a[dep][i].y);
if (x!=y) fa[x]=y,a[dep][i].k=;
}
//删点,找出必连边(k=3)
rep(i,,m) if (a[dep][i].k==) a[dep][i].z=-inf;
rep(i,,n) fa[i]=i;
sort(a[dep]+,a[dep]++m,cmp);
rep(i,,m) if (a[dep][i].k!=){
int x=find(a[dep][i].x),y=find(a[dep][i].y);
if (x!=y) {
fa[x]=y;
if (a[dep][i].k!=) a[dep][i].k=;
}
}
//重建,把必连边(k=3)取为答案,将两端点缩为一个点。
rep(i,,n) fa[i]=i;
rep(i,,m) if (a[dep][i].k==){
data &c=a[dep][i];
int x=find(c.x),y=find(c.y);
if (x!=y) fa[x]=y, ans+=c.z;
}
int nn=,nm=;
rep(i,,n) p[i]=;
rep(i,,n) if (!p[find(i)]) p[find(i)]=++nn;
rep(i,,m) if (a[dep][i].k!=){
int x=find(a[dep][i].x),y=find(a[dep][i].y);
data &c=a[dep][i];
if (x!=y) a[dep][++nm]=(data){p[x],p[y],c.z,c.k,c.id};
}
int mid=(l+r)/;
cdq(dep+,l,mid,nn,nm,ans);
cdq(dep+,mid+,r,nn,nm,ans);
}
int main(){
n=read(); m=read(); Q=read();
int x,y; ll z;
rep(i,,m){
x=read(); y=read(); z=read();
a[][i]=(data){x,y,z,,i};
}
rep(i,,Q){
x=read(); y=read();
b[i]=(node){x,y,i};
}
rep(i,,m) dis[a[][i].id]=a[][i].z;
cdq(,,Q,n,m,);
return ;
}