BZOJ2001: [Hnoi2010]City 城市建设

BZOJ

题意

给你一张 n n 个点 m m 条边的无向联通图和 Q Q 个询问,每次询问永久性的修改一条边的边权,问每次修改后改图的最小生成树的权值是多少;

题解

拿到题第一反应这不裸的线段树分治加个LCT吗,然后码码码码码,码了150多行交了一发wa,改了一下40,再来一下80,然后T了两组再也没涨过;一看题解原来是CDQ分治加神奇的缩点加速(老前辈们的并查集为什么都是又用启发式合并又用路径压缩);
为什么说正解是神奇的缩点加速呢,这题是这么想的,CDQ分治递归处理子问题时先把区间里询问影响的边拿出来做 C o n t r a c t i o n Contraction - R e d u c t i o n Reduction 操作:先把询问影响的边的权值设为 I N F -INF ,然后做一次 M S T MST , M S T MST 上的权值非询问边接下来一定会出现在 M S T MST 上(考虑因为询问边的权值已经设成了最小,如果询问边能代替这些在 M S T MST 上的非询问边,那么一定会先加进去的),所以直接把这些边的权值累加进答案里,然后将这些边构成的联通块缩成一个点,多余的边就直接删去只保留询不在联通块里的边,接下来再把询问边的边权生成 I N F INF ,再做一次 M S T MST ,只保留 M S T MST 上的边和询问边;在这两次操作过后边数点数都大大减少,一直递归下去,到了 L = R L=R 时,点数边数已经非常少了,这个时候只需要永久修改当前询问边权,再做一次 M S T MST 便能很快的得到答案;复杂度不会算

线段树分治+LCT
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=5e5+10;
int n,m,Q,top;
int last[N];
struct Edge {
	int u,v,w,id;
}E[N>>1];
vector<Edge> V[N<<2];
struct Data {
	int id,w,type;
	Data () {}
	Data (int a,int b,int c) :id(a),w(b),type(c) {}
}ST[N];
#define L son[rt][0]
#define R son[rt][1]
struct LinkCutTree {
    bool rev[N];
    int son[N][2],fa[N],w[N],ID[N];
    bool Isroot(int rt) {
        return son[fa[rt]][0]!=rt&&son[fa[rt]][1]!=rt;
    }
    bool Side(int rt,int f) {
        return son[f][0]==rt?0:1;
    }
    void Pushup(int rt) {
        ID[rt]=rt;
        if(w[ID[L]]>w[ID[rt]]) ID[rt]=ID[L];
        if(w[ID[R]]>w[ID[rt]]) ID[rt]=ID[R];
	}
    void Pushdown(int rt) {
        if(rev[rt]) {
            swap(L,R);
            rev[L]^=1; rev[R]^=1; rev[rt]^=1;
        }
    }
    void Push(int rt) {
        if(!Isroot(rt)) Push(fa[rt]);
        Pushdown(rt);
    }
    void Rotate(int rt) {
        int f=fa[rt],to=Side(rt,f),ano=son[rt][to^1],fto=Side(f,fa[f]);
        if(!Isroot(f)) son[fa[f]][fto]=rt;
        fa[rt]=fa[f];
        fa[ano]=f; son[f][to]=ano;
        fa[f]=rt; son[rt][to^1]=f;
        Pushup(f); Pushup(rt);
    }
    void Splay(int rt) {
        Push(rt);
        while(!Isroot(rt)) {
            if(Side(rt,fa[rt])==Side(fa[rt],fa[fa[rt]])&&!Isroot(fa[rt])&&!Isroot(fa[fa[rt]])) Rotate(fa[rt]);
            Rotate(rt);
        }
    }
    void Access(int rt) {
        for(int t=0;rt;t=rt,rt=fa[rt]) {
            Splay(rt);
            R=t;
            Pushup(rt);
        }
    }
    void Makeroot(int rt) {
        Access(rt);
        Splay(rt);
        rev[rt]^=1;
    }
    void Split(int x,int y) {
        Makeroot(x);
        Access(y);
        Splay(y);
    }
    void Cut(int x,int y) {
        Split(x,y);
        fa[x]=son[y][0]=0;
        Pushup(y);
    }
    void Link(int x,int y) {
        Makeroot(x);
        fa[x]=y;
    }
    int Find(int rt) {
    	Access(rt);
		Splay(rt);
		while(L) rt=L;
		return rt; 
    }
    int Query(int x,int y) {
    	Split(x,y);
    	return ID[y];
    }
}LCT;
void Modify(int l,int r,int o,int ql,int qr,Edge A) {
	if(ql<=l&&r<=qr) {
		V[o].push_back(A);
		return;
	}
	int mid=l+r>>1;
	if(ql<=mid) Modify(l,mid,o<<1,ql,qr,A);
	if(qr>mid) Modify(mid+1,r,o<<1|1,ql,qr,A);
}
void DAC(int l,int r,int o,LL val) {
	int now=top;
	for(int i=0;i<(int)V[o].size();++i) {
		int u=V[o][i].u,v=V[o][i].v,w=V[o][i].w,id=V[o][i].id;
		int x=LCT.Find(u),y=LCT.Find(v);
		if(x!=y) {
			ST[++top]=Data(id,LCT.w[n+id],0); LCT.w[n+id]=w;
			LCT.Link(u,n+id); LCT.Link(n+id,v);
			val+=w;
		}
		else {
			int t=LCT.Query(u,v);
			if(LCT.w[t]>w) {
				LCT.Cut(E[t-n].u,t); LCT.Cut(t,E[t-n].v);
				ST[++top]=Data(t-n,LCT.w[t],1); val-=LCT.w[t];
				ST[++top]=Data(id,LCT.w[n+id],0); LCT.w[n+id]=w;
				LCT.Link(u,n+id); LCT.Link(n+id,v);
			 	val+=w;
			}
		}
	}
	int mid=l+r>>1;
	if(l==r) {
		if(l>m) printf("%lld\n",val);
	}
	else DAC(l,mid,o<<1,val),DAC(mid+1,r,o<<1|1,val);
	while(top!=now) {
		int t=ST[top].id;
		LCT.w[t+n]=ST[top].w; LCT.ID[t+n]=t+n; 
		if(!ST[top].type) {
			LCT.Cut(E[t].u,t+n); 
			LCT.Cut(t+n,E[t].v);
		}
		else {
			LCT.Link(E[t].u,t+n);
			LCT.Link(t+n,E[t].v);
		}
		--top;
	}
}
int main() {
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1;i<=m;++i) {
		last[i]=1; E[i].id=i; LCT.ID[i+n]=i+n;
		scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
	}
	Q+=m;
	for(int i=m+1;i<=Q;++i) {
		int k,d; scanf("%d%d",&k,&d);
		Modify(1,Q,1,last[k],i-1,E[k]);
		last[k]=i; E[k].w=d;
	}
	for(int i=1;i<=m;++i) Modify(1,Q,1,last[i],Q,E[i]);
	DAC(1,Q,1,0);
	return 0;
}
CDQ分治
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e4+10,M=5e4+10,INF=2e9;
int n,m,Q;
int F[N],W[M],ID[M];
LL ANS[M];
struct Data {
	int id,w;
}A[M];
struct Edge {
	int u,v,w,id;
}E[20][M],G[M],tmp[M];
int Find(int a) {
	return F[a]==a?a:F[a]=Find(F[a]);
}
bool cmp(Edge A,Edge B) {
	return A.w<B.w;
}
void Init(int m) {
	for(int i=1;i<=m;++i) F[G[i].u]=G[i].u,F[G[i].v]=G[i].v;
}
LL Contraction(int &m) {
	Init(m); sort(G+1,G+m+1,cmp);
	int cnt=0; LL res=0;
	for(int i=1;i<=m;++i) if(Find(G[i].u)!=Find(G[i].v)) F[F[G[i].u]]=F[G[i].v],tmp[++cnt]=G[i];
	for(int i=1;i<=cnt;++i) F[tmp[i].u]=tmp[i].u,F[tmp[i].v]=tmp[i].v;
	for(int i=1;i<=cnt;++i) if(tmp[i].w!=-INF) F[Find(tmp[i].u)]=Find(tmp[i].v),res+=tmp[i].w;
	cnt=0;
	for(int i=1;i<=m;++i) if(Find(G[i].u)!=Find(G[i].v)) {
		tmp[++cnt]=G[i];
		ID[G[i].id]=cnt;
		tmp[cnt].u=F[G[i].u];
		tmp[cnt].v=F[G[i].v];
	}
	m=cnt;
	for(int i=1;i<=m;++i) G[i]=tmp[i];
	return res;
}
void Reduction(int &m) {
	Init(m); sort(G+1,G+m+1,cmp);
	int cnt=0;
	for(int i=1;i<=m;++i) {
		if(Find(G[i].u)!=Find(G[i].v)) {
			F[F[G[i].u]]=F[G[i].v];
			tmp[++cnt]=G[i];
			ID[G[i].id]=cnt;
		}
		else if(G[i].w==INF) {
			tmp[++cnt]=G[i];
			ID[G[i].id]=cnt;
		}
	}
	m=cnt;
	for(int i=1;i<=m;++i) G[i]=tmp[i];
}
void DAC(int l,int r,int dep,int m,LL res) {
	if(l==r) W[A[l].id]=A[l].w;
	for(int i=1;i<=m;++i) {
		E[dep][i].w=W[E[dep][i].id];
		G[i]=E[dep][i]; ID[G[i].id]=i;
	}
	if(l==r) {
		Init(m); sort(G+1,G+m+1,cmp);
		for(int i=1;i<=m;++i) if(Find(G[i].u)!=Find(G[i].v)) F[F[G[i].u]]=F[G[i].v],res+=G[i].w;
		ANS[l]=res;
		return;
	}
	for(int i=l;i<=r;++i) G[ID[A[i].id]].w=-INF;
	res+=Contraction(m);
	for(int i=l;i<=r;++i) G[ID[A[i].id]].w=INF;
	Reduction(m);
	for(int i=1;i<=m;++i) E[dep+1][i]=G[i];
	int mid=l+r>>1;
	DAC(l,mid,dep+1,m,res); DAC(mid+1,r,dep+1,m,res);
}
int main() {
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1;i<=m;++i) {
		scanf("%d%d%d",&E[0][i].u,&E[0][i].v,&E[0][i].w);
		E[0][i].id=i; W[i]=E[0][i].w;
	}
	for(int i=1;i<=Q;++i) scanf("%d%d",&A[i].id,&A[i].w);
	DAC(1,Q,0,m,0);
	for(int i=1;i<=Q;++i) printf("%lld\n",ANS[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/CIao_015/article/details/83510683
今日推荐