记录编号 129798 评测结果 AAAAAAAAAAAAAAAAAAAA
题目名称 [HNOI 2010]城市建设 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 9.738 s
提交时间 2014-10-20 22:23:06 内存使用 1.27 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<set>
using namespace std;
const int SIZEN=50100;
typedef long long LL;
class UFS{
public:
	int fa[SIZEN];
	void init(int n){for(int i=0;i<=n;i++) fa[i]=i;}
	int grand(int x){
		return fa[x]==x?x:fa[x]=grand(fa[x]);
	}
	bool merge(int a,int b){
		int ga=grand(a),gb=grand(b);
		if(ga==gb) return false;
		fa[ga]=gb;
		return true;
	}
}ufs;
class EDGE{
public:
	int id;
	int u,v,cost;
	bool del,uni;
	EDGE(){id=u=v=cost=del=uni=0;}
};
bool operator < (EDGE a,EDGE b){
	return a.cost<b.cost;
}
class OPT{
public:
	int id;
	int cost;
};
OPT ops[SIZEN];
int N,M,Q;
LL ans[SIZEN];
vector<EDGE> E;
void read(void){
	scanf("%d%d%d",&N,&M,&Q);
	EDGE e;
	for(int i=1;i<=M;i++){
		scanf("%d%d%d",&e.u,&e.v,&e.cost);
		e.id=i;
		E.push_back(e);
	}
	for(int i=1;i<=Q;i++){
		OPT &q=ops[i];
		scanf("%d%d",&q.id,&q.cost);
	}
}
void solve(int l,int r,vector<EDGE> E,int n,LL sum,int upd_l,int upd_r){
	map<int,int> lis;
	if(l==r) upd_r=r;
	//进行更新
	for(int i=0;i<E.size();i++) lis.insert(make_pair(E[i].id,i));
	for(int i=upd_l;i<=upd_r;i++){
		OPT &q=ops[i];
		if(lis.count(q.id)){
			int p=lis[q.id];
			E[p].cost=q.cost;
		}
	}
	//将边按照权值排序
	sort(E.begin(),E.end());
	//只剩下了一个询问,暴力求当前可行边集
	if(l==r){
		ufs.init(n+10);
		for(int i=0;i<E.size();i++){
			EDGE &e=E[i];
			if(ufs.merge(e.u,e.v)) sum+=e.cost;
		}
		ans[l]=sum;
		return;
	}
	set<int> es;//把l~r之间操作的边扔进去
	for(int i=l;i<=r;i++) es.insert(ops[i].id);
	//R操作,去掉一些边
	/*这次,将l~r之间询问边的边权赋为无穷大,那么E中不在MST中的边,
	必不在l~r间任一查询答案的MST中*/
	ufs.init(n+10);
	for(int i=0;i<E.size();i++){
		EDGE &e=E[i];
		if(es.count(e.id)) continue;//跳过询问边,相当于将边权赋为无穷大
		if(!ufs.merge(e.u,e.v)) e.del=true;
	}
	//C操作,收缩一些点
	/*这次,将l~r之间询问边的边权设为无穷小,那么E中在MST中的边,
	必然在l~r间任一查询答案的MST中
	*/
	ufs.init(n+10);
	for(int i=0;i<E.size();i++){//先期插入所有询问边,相当于将边权赋为无穷小
		EDGE &e=E[i];
		if(es.count(e.id)) ufs.merge(e.u,e.v);
	}
	for(int i=0;i<E.size();i++){
		EDGE &e=E[i];
		if(es.count(e.id)||e.del) continue;
		if(ufs.merge(e.u,e.v)) e.uni=true,sum+=e.cost;//该边一定在l~r所有查询答案的MST中
	}
	//重新给点标号,建出新图,自然会扔掉一些边
	ufs.init(n+10);
	for(int i=0;i<E.size();i++) if(E[i].uni) ufs.merge(E[i].u,E[i].v);//缩点
	map<int,int> mp;int tot=0;
	for(int i=1;i<=n;i++){//给未缩的点编号
		int g=ufs.grand(i);
		if(g==i) mp[i]=++tot;
	}
	vector<EDGE> new_E;
	for(int i=0;i<E.size();i++){
		EDGE e=E[i];
		if(e.del||e.uni) continue;//一定在和一定不在答案中的边不会被纳入考虑
		e.u=mp[ufs.grand(e.u)],e.v=mp[ufs.grand(e.v)];
		new_E.push_back(e);
	}
	int mid=(l+r)/2;
	solve(l,mid,new_E,tot,sum,l,0);
	solve(mid+1,r,new_E,tot,sum,l,mid);
}
int main(){
	freopen("hnoi2010_city.in","r",stdin);
	freopen("hnoi2010_city.out","w",stdout);
	read();
	solve(1,Q,E,N,0,1,0);
	for(int i=1;i<=Q;i++) printf("%lld\n",ans[i]);
	return 0;
}