您的位置:首页 > 其它

bzoj2001 [Hnoi2010]City 城市建设

2017-01-20 10:35 302 查看
【题意】

n点m边q次操作,每次修改一条边的边权并求最小生成树。

【数据范围】

n<=20000,m<=50000,q<=50000

【思路】

神题。

[方法一]CDQ分治+LCT(TLE)

类似于bzoj3237,首先把当前区间没有涉及的边加入

分治左区间:把左区间无右区间有的边加入,分治左区间,把刚刚加入的边倒序复原

分治右区间:因为修改叠加,故依序执行左区间的修改,然后把右区间无左区间有的边加入,分治右区间,把刚刚加入的边倒序复原

复原方法:记录每条加入的边删除了哪条边

于是问题转化为加边并维护最小生成树,使用LCT

随机极限数据跑了4s,常数过大

[方法二]CDQ分治+重构图-动态最小生成树(AC)

核心思想:把当前区间没有涉及的边进行优化

优化过程包含2个操作:删除无用边,添加必要边并缩点

删除无用边:把当前区间涉及的边的权值改为+∞,做MST,把区间外的没有加入MST的边删除,因为原MST上这些边更不可能加入

添加必要边并缩点:把当前区间涉及的边的权值改为-∞,做MST,把区间外的加入MST的边直接加入,更新答案,因为原MST上这些边更会加入;然后把1个连通块缩成1个点,相应修改边的顶点标号

这样就进行了边的优化,建立分层图存储每一层分治的新图,直接分治左右区间即可

【时间复杂度】

[方法一]O(m log^2m)

[方法二]O(玄学)

【方法一】

//CDQ分治+LCT(TLE)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 70010
#define M 50010
#define ll long long
using namespace std;

struct bb{int x, y, z;}b[M];
struct cc{int x, y;}c[M];
struct dd{int x, p;}d[1000010];
int n, m, q, a
, fa
, ch
[2], rev
, mx
, mxp
, isroot
, size
, l, flag[M],
MX, MXP, x, y, ss;
ll ans;

inline int read(){
int x=0, f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}

void updateRev(int i){
if(!i)return;
swap(ch[i][0], ch[i][1]); rev[i]^=1;
}
void pushdownRev(int i){
if(rev[i]){
updateRev(ch[i][0]); updateRev(ch[i][1]);
rev[i]=0;
}
}
void update(int i){
size[i]=size[ch[i][0]]+size[ch[i][1]]+1;
mx[i]=a[i]; mxp[i]=i;
if(mx[i]<mx[ch[i][0]]){mx[i]=mx[ch[i][0]]; mxp[i]=mxp[ch[i][0]];}
if(mx[i]<mx[ch[i][1]]){mx[i]=mx[ch[i][1]]; mxp[i]=mxp[ch[i][1]];}
}
void P(int x){if(!isroot[x])P(fa[x]); pushdownRev(x);}
void rotate(int x){
int y=fa[x], kind=ch[y][1]==x;
ch[y][kind]=ch[x][!kind];
if(ch[x][!kind])fa[ch[x][!kind]]=y;
ch[x][!kind]=y;
fa[x]=fa[y];
if(isroot[y]){isroot[x]=1; isroot[y]=0;}
else ch[fa[y]][ch[fa[y]][1]==y]=x;
fa[y]=x;
update(y);
}
void splay(int x){
P(x);
while(!isroot[x]){
int f=fa[x], ff=fa[f];
if(!isroot[f]){
if((ch[f][0]==x)==(ch[ff][0]==f)){rotate(f); rotate(x);}
else{rotate(x); rotate(x);}
}else rotate(x);
}
update(x);
}
void access(int x){
int y=0;
while(x){
splay(x);
isroot[ch[x][1]]=1;
ch[x][1]=y; isroot[y]=0;
update(x);
y=x; x=fa[x];
}
}
void memroot(int x){access(x); splay(x); updateRev(x);}
void link(int x, int y){memroot(x); fa[x]=y;}
void cut(int x, int y){
memroot(x); access(y); splay(y);
isroot[x]=1; fa[x]=ch[y][0]=0; update(y);
}
int find(int x, int y){
memroot(x); access(y); splay(y); int xx=y;
while(ch[xx][0])xx=ch[xx][0]; return x==xx;
}
void check(int x, int y){
memroot(x); access(y); splay(y);
MX=mx[y]; MXP=mxp[y];
}

void fz(int L, int R){
int x, y, p=-1;
if(L==R){
a[n+c[L].x]=mx[n+c[L].x]=c[L].y; x=b[c[L].x].x; y=b[c[L].x].y;
if(!find(x, y)){p=0; ans+=a[n+c[L].x]; link(x, n+c[L].x); link(y, n+c[L].x);}
else{
check(x, y);
if(a[n+c[L].x]<MX){
p=MXP; ans+=a[n+c[L].x]-MX;
cut(b[p-n].x, p); cut(b[p-n].y, p);
link(x, n+c[L].x); link(y, n+c[L].x);
}
}
printf("%lld\n", ans);
if(p==-1)return;
ans-=a[n+c[L].x]-a[p]; cut(x, n+c[L].x); cut(y, n+c[L].x);
if(p){link(b[p-n].x, p); link(b[p-n].y, p);}
return;
}
int mid=(L+R)>>1, op, cl;

ss++; op=l+1;
for(int i=L; i<=mid; i++)flag[c[i].x]=ss;
for(int i=mid+1; i<=R; i++)if(flag[c[i].x]<ss){
x=b[c[i].x].x; y=b[c[i].x].y;
if(!find(x, y)){d[++l].x=c[i].x; d[l].p=0; ans+=a[n+c[i].x]; link(x, n+c[i].x); link(y, n+c[i].x);}
else{
check(x, y);
if(a[n+c[i].x]<MX){
p=MXP; d[++l].x=c[i].x; d[l].p=p; ans+=a[n+c[i].x]-MX;
cut(b[p-n].x, p); cut(b[p-n].y, p);
link(x, n+c[i].x); link(y, n+c[i].x);
}
}
}
cl=l;
fz(L, mid);
for(int i=cl; i>=op; i--){
ans-=a[n+d[i].x]-a[d[i].p]; x=b[d[i].x].x; y=b[d[i].x].y;
cut(x, n+d[i].x); cut(y, n+d[i].x);
if(d[i].p){link(b[d[i].p-n].x, d[i].p); link(b[d[i].p-n].y, d[i].p);}
}

for(int i=L; i<=mid; i++)a[n+c[i].x]=c[i].y;
ss++; op=l+1;
for(int i=mid+1; i<=R; i++)flag[c[i].x]=ss;
for(int i=L; i<=mid; i++)if(flag[c[i].x]<ss){
x=b[c[i].x].x; y=b[c[i].x].y;
if(!find(x, y)){d[++l].x=c[i].x; d[l].p=0; ans+=a[n+c[i].x]; link(x, n+c[i].x); link(y, n+c[i].x);}
else{
check(x, y);
if(a[n+c[i].x]<MX){
p=MXP; d[++l].x=c[i].x; d[l].p=p; ans+=a[n+c[i].x]-MX;
cut(b[p-n].x, p); cut(b[p-n].y, p);
link(x, n+c[i].x); link(y, n+c[i].x);
}
}
}
cl=l;
fz(mid+1, R);
for(int i=cl; i>=op; i--){
ans-=a[n+d[i].x]-a[d[i].p]; x=b[d[i].x].x; y=b[d[i].x].y;
cut(x, n+d[i].x); cut(y, n+d[i].x);
if(d[i].p){link(b[d[i].p-n].x, d[i].p); link(b[d[i].p-n].y, d[i].p);}
}

}

int main(){
n=read(); m=read(); q=read();
for(int i=1; i<=m; i++){b[i].x=read(); b[i].y=read(); b[i].z=read();}
for(int i=1; i<=q; i++){c[i].x=read(); c[i].y=read();}
for(int i=1; i<=n+m; i++){
fa[i]=ch[i][0]=ch[i][1]=rev[i]=a[i]=mx[i]=0; isroot[i]=size[i]=1; mxp[i]=i;
}
a[0]=0; for(int i=1; i<=m; i++)a[n+i]=mx[n+i]=b[i].z;
memset(flag, 0, sizeof(flag));
for(int i=1; i<=q; i++)flag[c[i].x]=1;
ans=0;
for(int i=1; i<=m; i++)if(!flag[i]){
x=b[i].x; y=b[i].y;
if(!find(x, y)){ans+=a[n+i]; link(x, n+i); link(y, n+i);}
else{
check(x, y);
if(a[n+i]<MX){
ans+=a[n+i]-MX;
cut(b[MXP-n].x, MXP); cut(b[MXP-n].y, MXP);
link(x, n+i); link(y, n+i);
}
}
}
memset(flag, 0, sizeof(flag)); l=ss=0;
fz(1, q);
return 0;
}【方法二】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 50010
#define inf 2147483647
#define ll long long
using namespace std;

struct edge{int x, y, z, id;}a[20]
, b
, B
;
struct cc{int x, y;}c
;
int n, m, q, sv[20], se[20], f
, posv
, flag
, lv1, le1, w
, W
;
ll sum;

inline int read(){
int x=0, f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}

bool cmp(edge a, edge b){return a.z<b.z;}

int gether(int x){return f[x]?f[x]=gether(f[x]):x;}

void del(int lv, int le){
for(int i=1; i<=lv; i++)f[i]=0;
for(int i=1; i<=le; i++)flag[i]=0;
for(int i=1; i<=le; i++)b[i].id=i;
sort(b+1, b+1+le, cmp);
int x, y, xx, yy;
for(int i=1; i<=le; i++){
x=b[i].x; y=b[i].y; xx=gether(x); yy=gether(y);
if(xx!=yy){f[yy]=xx; flag[b[i].id]=1;}
}
for(int i=1; i<=le; i++)if(b[i].z==inf)flag[b[i].id]=1;
le1=0;
for(int i=1; i<=le; i++)if(flag[i])b[++le1]=B[i];
}
void ins(int lv, int le){
for(int i=1; i<=lv; i++)f[i]=0;
for(int i=1; i<=le; i++)flag[i]=0;
for(int i=1; i<=le; i++)b[i].id=i;
sort(b+1, b+1+le, cmp);
int x, y, xx, yy;
for(int i=1; i<=le; i++){
x=b[i].x; y=b[i].y; xx=gether(x); yy=gether(y);
if(xx!=yy){f[yy]=xx; flag[b[i].id]=1;}
}
for(int i=1; i<=le; i++)if(b[i].z==-inf)flag[b[i].id]=0;
for(int i=1; i<=lv; i++)f[i]=0;
for(int i=1; i<=le; i++)if(flag[i]){
x=B[i].x; y=B[i].y; xx=gether(x); yy=gether(y); if(xx!=yy)f[yy]=xx;
}
lv1=le1=sum=0;
for(int i=1; i<=lv; i++)if(gether(i)==i)posv[i]=++lv1;
for(int i=1; i<=lv; i++)posv[i]=posv[gether(i)];
for(int i=1; i<=le; i++)if(!flag[i]&&posv[B[i].x]!=posv[B[i].y]){
b[++le1].x=posv[B[i].x]; b[le1].y=posv[B[i].y]; b[le1].z=B[i].z; b[le1].id=B[i].id;
}else sum+=B[i].z;
}

void fz(int L, int R, int P, ll ans){
int lv=sv[P], le=se[P], x, y, xx, yy;
if(L==R)w[c[L].x]=c[L].y;
for(int i=1; i<=le; i++)a[P][i].z=w[a[P][i].id];
if(L==R){
for(int i=1; i<=lv; i++)f[i]=0;
for(int i=1; i<=le; i++)b[i]=a[P][i];
sort(b+1, b+1+le, cmp);
for(int i=1; i<=le; i++){
x=b[i].x; y=b[i].y; xx=gether(x); yy=gether(y);
if(xx!=yy){f[yy]=xx; ans+=b[i].z;}
}
printf("%lld\n", ans);
return;
}

for(int i=1; i<=le; i++)B[i]=b[i]=a[P][i];
for(int i=L; i<=R; i++){if(w[c[i].x]<inf)W[c[i].x]=w[c[i].x]; w[c[i].x]=inf;}
for(int i=1; i<=le; i++)b[i].z=w[b[i].id];
del(lv, le); le=le1;
for(int i=1; i<=le; i++)B[i]=b[i];
for(int i=L; i<=R; i++)w[c[i].x]=-inf;
for(int i=1; i<=le; i++)b[i].z=w[b[i].id];
ins(lv, le); lv=lv1; le=le1;
sv[P+1]=lv; se[P+1]=le; ans+=sum;
for(int i=1; i<=le; i++)a[P+1][i]=b[i];
for(int i=L; i<=R; i++)w[c[i].x]=W[c[i].x];

int mid=(L+R)>>1;
fz(L, mid, P
d6f3
+1, ans); fz(mid+1, R, P+1, ans);
}

int main(){
n=read(); m=read(); q=read();
for(int i=1; i<=m; i++){b[i].x=read(); b[i].y=read(); b[i].z=w[i]=read();}
for(int i=1; i<=q; i++){c[i].x=read(); c[i].y=read();}
sv[1]=n; se[1]=m;
for(int i=1; i<=m; i++){a[1][i]=b[i]; a[1][i].id=i;}
fz(1, q, 1, 0);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: