BZOJ 2001([Hnoi2010]City 城市建设-CDQ重构图-动态最小生成树)

2001: [Hnoi2010]City 城市建设

Time Limit: 20 Sec   Memory Limit: 162 MB
Submit: 217   Solved: 100
[ Submit][ Status]

Description

PS国是一个拥有诸多城市的大国,国王Louis为城市的交通建设可谓绞尽脑汁。Louis可以在某些城市之间修建道路,在不同的城市之间修建道路需要不同的花费。Louis希望建造最少的道路使得国内所有的城市连通。但是由于某些因素,城市之间修建道路需要的花费会随着时间而改变,Louis会不断得到某道路的修建代价改变的消息,他希望每得到一条消息后能立即知道使城市连通的最小花费总和, Louis决定求助于你来完成这个任务。

Input

文件第一行包含三个整数N,M,Q,分别表示城市的数目,可以修建的道路个数,及收到的消息个数。 接下来M行,第i+1行有三个用空格隔开的整数Xi,Yi,Zi(1≤Xi,Yi≤n, 0≤Zi≤50000000),表示在城市Xi与城市Yi之间修建道路的代价为Zi。接下来Q行,每行包含两个数k,d,表示输入的第k个道路的修建代价修改为d(即将Zk修改为d)。

Output

输出包含Q行,第i行输出得知前i条消息后使城市连通的最小花费总和。

Sample Input

5 5 3
1 2 1
2 3 2
3 4 3
4 5 4
5 1 5
1 6
1 1
5 3

Sample Output

14
10
9

HINT

【数据规模】
对于20%的数据, n≤1000,m≤6000,Q≤6000。
有20%的数据,n≤1000,m≤50000,Q≤8000,修改后的代价不会比之前的代价低。
对于100%的数据, n≤20000,m≤50000,Q≤50000。

Source

Day2




高端洋气上档次的动态最小生成树。。。

想当年听7k+在WC上侃侃而谈时SB的听不懂。。。。

好吧。。。

总而言之有2个操作

Contraction & Reduction

这个我也不废话了。。。

但是这题需要重构边图。。。一开始看到想吐血。。

后来发现边的存储形式是(x,y,w) 和不是邻接表 这样就随便了。。。(喂)

细节是硬伤。。。。

// 动态最小生成树--很麻烦的题目。。。先理解再说吧,,,
// 考场出这种题目是什么心态。。。。。。、 
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define F (100000007)
#define MAXN (20000+10)
#define MAXM (50000+10)
#define MAXQ (50000+10)
#define MAXZi (50000000)
#define INF (50000000+1)
#define inf (-1)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
int n,m,q;
/*
struct E
{
	int edge[MAXM],next[MAXM],pre[MAXN],size;
	ll weight[MAXM];
	E(){edge[MAXN]=next[MAXN]=(0);size=0;}
	void addedge(int u,int v,ll w)
	{
		edge[++size]=v;
		weight[size]=w;
		next[size]=pre[u];
		pre[u]=size;
	}
	void addedge2(int u,int v,ll w){addedge(u,v,w),addedge(v,u,w);	}
}e,e2;*/
struct E
{
	int x,y;
	ll w;
}e[MAXM*30],*e_tail=e;
struct comm
{
	int num;
	ll val;
}ask[MAXQ],back[MAXQ*30],*back_tail=back;
ll ans[MAXQ]={0};
struct unionset
{
	int father[MAXN];
	void init(int n){For(i,n) father[i]=i;	}
	int getfather(int x)
	{
		if (father[x]==x) return x;
		return father[x]=getfather(father[x]);
	}
	bool union2(int x,int y)
	{
		if (getfather(x)==getfather(y)) return 0;
		father[getfather(x)]=getfather(y);return 1;
	}
}ufs;
int eidx[MAXM*10],newV[MAXN],newE[MAXM];
bool cmp(int i,int j){return e_tail[i].w<e_tail[j].w;}
void solve(int n,E *_e,int m,int l,int r,ll inherent) //e_tail表示上次e的结尾 
{
	e_tail+=m;
	E *e=e_tail;
	copy(_e,e_tail,e);
	if (l==r)
	{
		e[ask[l].num].w=ask[l].val;
		ufs.init(n);
		Rep(i,m) eidx[i]=i;sort(eidx,eidx+m,cmp);
		Rep(i,m)
		{
			int id=eidx[i];
			if (ufs.union2(e[id].x,e[id].y)) inherent+=e[id].w;
		}
		ans[l]=inherent;
		
		e_tail-=m;
		return;
	}
	// Con-must edge
	static bool b[MAXM]={0};
	memset(b,0,sizeof(b));
	Fork(i,l,r) e[ask[i].num].w=inf;
	ufs.init(n);
	Rep(i,m) eidx[i]=i;sort(eidx,eidx+m,cmp);
	Rep(i,m)
	{
		int id=eidx[i];
		if (ufs.union2(e[id].x,e[id].y)&&e[id].w!=inf) inherent+=e[id].w,b[id]=1;
	}
	ufs.init(n);Rep(i,m) if (b[i]) ufs.union2(e[i].x,e[i].y); //改动边不缩点	
	int n2=0;
	For(i,n) if (ufs.getfather(i)==i) newV[i]=++n2;
	For(i,n) if (ufs.getfather(i)^i) newV[i]=newV[ufs.getfather(i)];
	Rep(i,m) e[i].x=newV[e[i].x],e[i].y=newV[e[i].y];
	
	// Red-impossible edge
	Fork(i,l,r) e[ask[i].num].w=INF;
	ufs.init(n2);
	Rep(i,m) eidx[i]=i;sort(eidx,eidx+m,cmp);
	Rep(i,m)
	{
		int id=eidx[i];
		if (ufs.union2(e[id].x,e[id].y)||e[id].w==INF) b[id]=1;else b[id]=0;
	}//若 x=y 则b[i]=0 保证不出先当前修改边 
	int m2=0; //边从0标号 m2比实际值大1(Rep) 
	Rep(i,m) if (b[i]) newE[i]=m2++;
	Fork(i,l,r) e[ask[i].num].w=_e[ask[i].num].w,ask[i].num=newE[ask[i].num];
	Rep(i,m) if (b[i]) e[newE[i]]=e[i];
	
	{
		int m=l+r>>1,len=m-l+1;
		comm *back_head=back_tail;
		back_tail+=len;
		copy(ask+l,ask+m+1,back_head);
		if (l<=m) solve(n2,e,m2,l,m,inherent);
		copy(back_head,back_head+len,ask+l);
		back_tail-=len;
		Fork(i,l,m) e[ask[i].num].w=ask[i].val;
		if (m<r) solve(n2,e,m2,m+1,r,inherent);
	}
	e_tail-=m;
	
}
int main()
{
//	freopen("bzoj2001.in","r",stdin);
	scanf("%d%d%d",&n,&m,&q);
	Rep(i,m) //保证备份的紧凑性 
	{
		scanf("%d%d%lld",&e[i].x,&e[i].y,&e[i].w);
	}
	Rep(i,q)
	{
		scanf("%d%lld",&ask[i].num,&ask[i].val);ask[i].num--;
	}
	solve(n,e,m,0,q-1,0);
	Rep(i,q) printf("%lld\n",ans[i]);
	
	
	return 0;
}






你可能感兴趣的:(BZOJ 2001([Hnoi2010]City 城市建设-CDQ重构图-动态最小生成树))