[bzoj2001][Hnoi2010][City 城市建设] (cdq分治)

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。

Solution

考虑按时间分治

显然终止态为分治到一个时间点时,直接修改,并计算出最小生成树,得出答案

每次操作前,都进行两个操作

construction,缩必须边

reduction,删除无用边

#include <stdio.h>
#include <algorithm>
#define RG register
#define gg 0x7fffffff
#define N 20010
#define L 50010
int n,m,_q,a[L],sum[25],c[L],f[N],sz[N];
long long ans[N];
struct edg{
	int x,y,z,id;
}e[25][L],d[L],t[L];
struct que{
	int x,y;
}q[L];
bool cmp(edg u,edg v){
	return u.z<v.z;
}
int getp(RG int x){return f[x]==x?x:f[x]=getp(f[x]);}
inline void mrg(RG int x,RG int y){
	if(sz[x]<=sz[y])sz[y]+=sz[x],f[x]=y;
	else sz[x]+=sz[y],f[y]=x;
}
inline void clr(RG int tot){
	for(RG int i=1;i<=tot;i++){
		f[d[i].x]=d[i].x;
		f[d[i].y]=d[i].y;
		sz[d[i].x]=sz[d[i].y]=1;
	}
}
void con(RG int &tot,RG long long &cnt){
	RG int O=0;
	clr(tot);
	std::sort(d+1,d+1+tot,cmp);
	for(RG int i=1,x,y;i<=tot;i++){
		x=getp(d[i].x),y=getp(d[i].y);
		if(x!=y)mrg(x,y),t[++O]=d[i];
	}
	for(RG int i=1;i<=O;i++){
		f[t[i].x]=t[i].x;
		f[t[i].y]=t[i].y;
		sz[t[i].x]=sz[t[i].y]=1;
	}
	for(RG int i=1,x,y;i<=O;i++){
		x=getp(t[i].x),y=getp(t[i].y);
		if(t[i].z!=-gg&&x!=y)
			mrg(x,y),cnt+=t[i].z;
	}
	O=0;
	for(RG int i=1;i<=tot;i++)
		if(getp(d[i].x)!=getp(d[i].y)){
			t[++O]=d[i];
			c[d[i].id]=O;
			t[O].x=f[d[i].x];
			t[O].y=f[d[i].y];
		}
	tot=O;
	for(RG int i=1;i<=tot;i++)
		d[i]=t[i];
}
void red(RG int &tot){
	RG int O=0;
	clr(tot);
	std::sort(d+1,d+1+tot,cmp);
	for(RG int i=1,x,y;i<=tot;i++){
		x=getp(d[i].x),y=getp(d[i].y);
		if(x!=y)mrg(x,y),t[++O]=d[i],c[d[i].id]=O;
		else if(d[i].z==gg)t[++O]=d[i],c[d[i].id]=O;
	}
	tot=O;
	for(RG int i=1;i<=tot;i++)
		d[i]=t[i];
}
void cdq(RG int l,RG int r,RG int cur,RG long long cnt){
	RG int tot=sum[cur];
	if(l==r)a[q[l].x]=q[l].y;
	for(RG int i=1;i<=tot;i++)
		e[cur][i].z=a[e[cur][i].id];
	for(RG int i=1;i<=tot;i++)
		d[i]=e[cur][i],c[d[i].id]=i;
	if(l==r){
		ans[l]=cnt;
		clr(tot);
		std::sort(d+1,d+1+tot,cmp);
		for(RG int i=1,x,y;i<=tot;i++){
			x=getp(d[i].x),y=getp(d[i].y);
			if(x!=y)mrg(x,y),ans[l]+=d[i].z;
		}
		return;
	}
	for(RG int i=l;i<=r;i++)
		d[c[q[i].x]].z=-gg;
	con(tot,cnt);
	for(RG int i=l;i<=r;i++)
		d[c[q[i].x]].z=gg;
	red(tot);
	for(RG int i=1;i<=tot;i++)
		e[cur+1][i]=d[i];
	sum[cur+1]=tot;
	RG int mid=l+r>>1;
	cdq(l,mid,cur+1,cnt);cdq(mid+1,r,cur+1,cnt);
}
int main(){
	scanf("%d%d%d",&n,&m,&_q);
	for(RG int i=1;i<=m;i++){
		scanf("%d%d%d",&e[0][i].x,&e[0][i].y,&e[0][i].z);
		a[i]=e[0][i].z;
		e[0][i].id=i;
	}
	for(RG int i=1;i<=_q;i++)
		scanf("%d%d",&q[i].x,&q[i].y);
	sum[0]=m;
	cdq(1,_q,0,0);
	for(RG int i=1;i<=_q;i++)
		printf("%lld\n",ans[i]);
	return 0;
}

不知道为什么

好想自杀啊

时间: 2024-12-05 11:52:10

[bzoj2001][Hnoi2010][City 城市建设] (cdq分治)的相关文章

BZOJ2001 [Hnoi2010]City 城市建设 【CDQ分治 + kruskal】

题目链接 BZOJ2001 题解 CDQ分治神题... 难想难写.. 比较朴素的思想是对于每个询问都求一遍\(BST\),这样做显然会爆 考虑一下时间都浪费在了什么地方 我们每次求\(BST\)实际上就只有一条边不同,我们实际浪费了很多时间在处理相同的边上 那就考虑分治 对于一个待修改的边集,我们将其权值全部设为\(-\infty\),跑一遍\(BST\),此时其它边如果被选中,说明这些边在单独询问时也一定会被选,将这些边连的点缩点 同样,对于一个待修改的边集,我们将其权值全部设为\(\inft

BZOJ2001 [Hnoi2010]City 城市建设

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作.   本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! 题目链接:BZOJ2001 正解:CDQ分治+并查集 解题报告: 这道题的$CDQ$分治思想非常巧妙- 考虑我在处理区间$[l,r]$时的情况,我把在这一段区间中会被修改的边称为特殊边, 我先把特殊边的权值设为$-inf$,跑一遍$MST$,此时在$M

【HNOI2010】【BZOJ2001】City 城市建设

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

【bzoj2001】 Hnoi2010—City 城市建设

http://www.lydsy.com/JudgeOnline/problem.php?id=2001 (题目链接) 题意 给出一张无向图,$m$组操作,每次修改一条边的权值,对于每次操作输出修改之后的图的最小生成树边权和. Solution nnd开了半个小时的脑洞,然并卵.感谢这位大爷的代码与题解:http://blog.csdn.net/u013368721/article/details/39183033 我们对时间cdq分治,如何在每一层向下递归的时候减小问题规模呢,两个关键的操作:

BZOJ-2001-city城市建设-HNOI2010-CDQ分治

描述 给出有n个点, m条边的无向图, 每次修改一条边的权值, 求修改后的最小生成树的大小. 修改次数 ≤ 50000. 分析 还是CDQ分治, 但是有点特殊. 目前的CDQ分治还是停留在看题解看别人代码才理解的层面. 有一些边一定在部分修改后的最小生成树中, 这是优化的中心思想吧. 然后一个减少边的操作, 一个减少点的操作. 看课件吧. 减少点的方法是缩点, 用并查集. 一开始想用全局变量d, n, m, ans代替函数参数传递. 后来发现因为分治的缘故这样做是不行的. 代码

bzoj-2001 City 城市建设

题意: 给出一个n个结点m条边的带权无向连通图,有q次操作: 每次操作是修改一个边的权值,要求每次操作后输出这个图中最小生成树的权值和: n<=20000,m<=50000,q<=50000: 题解: 网上题解都是那些鬼畜的分治做法,每层求最小生成树将问题缩小到可以接受的范围: 不过那个方法不好理解并且难以推广,所以wyfcyx大爷提出了一种更加让人愉悦的做法: 首先这个问题不能直接用LCT维护,因为当删去一条边(边的权值变大)之后,我们无法知道这两个连通块之间是否还有更小边相连: 也就

【bzoj3672】[Noi2014]购票 斜率优化+CDQ分治+树的点分治

题目描述 给出一棵以1为根的带边权有根树,对于每个根节点以外的点$v$,如果它与其某个祖先$a$的距离$d$不超过$l_v$,则可以花费$p_vd+q_v$的代价从$v$到$a$.问从每个点到1花费的最小代价(中途可以经停其它点) 输入 第 1 行包含2个非负整数 n,t,分别表示城市的个数和数据类型(其意义将在后面提到).输入文件的第 2 到 n 行,每行描述一个除SZ之外的城市.其中第 v 行包含 5 个非负整数 $f_v,s_v,p_v,q_v,l_v$,分别表示城市 v 的父亲城市,它到

【BZOJ3456】【CDQ分治+FNT】城市规划

试题来源 2013中国国家集训队第二次作业 问题描述 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案. 好了, 这就是困扰阿狸的问题.

CDQ分治与整体二分小结

前言 这是一波强行总结. 下面是一波瞎比比. 这几天做了几道CDQ/整体二分,感觉自己做题速度好慢啊. 很多很显然的东西都看不出来 分治分不出来 打不出来 调不对 上午下午晚上的效率完全不一样啊. 完蛋.jpg 绝望.jpg. 关于CDQ分治 CDQ分治,求的是三维偏序问题都知道的. 求法呢,就是在分治外面先把一维变成有序 然后分治下去,左边(l,mid)关于右边(mid+1,r)就不存在某一维的逆序了,所以只有两维偏序了. 这个时候来一波"树状数组求逆序对"的操作搞一下二维偏序 就可