bzoj-2594 水管局长数据加强版

题意:

给出一个n个点m条边的无向图,边上有权值;

Q次询问,每次有两种操作:

1.求x,y两点路径上的最大值的最小值;

2.删除一条边;

保证删除的边存在,保证图时刻连通,保证不会出现重边和自环;

n≤100000,m≤1000000,Q≤100000;

题解:

这是一个动态图问题,但是由于询问操作的特殊性,我们也可以转化到树上做;

仔细看看不就是带删边的货车运输吗!

那么用LCT来维护最小生成树查询操作1就可以了;

但是LCT维护最小生成树是不能删边的;

考虑倒着处理询问,删边就成了加边;

加边会出现环,那么就将权值最大的边弹出去就好了;

弹边操作似乎比较恶心,那么将边转化成一个点,这个点连接两个点;

那么就把边权转化到点上,删除这个点的两条边就是了;

此题预处理比较糟糕(似乎离线处理的东西都这样);

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
#define Pt 330000
#define which(x) (ch[fa[x]][1]==x)
using namespace std;
struct node
{
	bool op;
	int x,y,val,no;
}Q[N];
struct edge
{
	int x,y,val;
	bool del;
	friend bool operator <(edge a,edge b)
	{
		if(a.x==b.x)
		return a.y<b.y;
		return a.x<b.x;
	}
}total[N*10],temp;
int fa[Pt],ch[Pt][2],val[Pt],ma[Pt],wma[Pt],ans[N],f[N];
bool rt[Pt],rev[Pt];
inline int read()
{
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9')	ch=getchar();
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x;
}
int cmp(edge a,edge b)
{
	if(a.del==b.del)
	return a.val<b.val;
	return a.del<b.del;
}
void Pushup(int x)
{
	ma[x]=max(val[x],max(ma[ch[x][0]],ma[ch[x][1]]));
	wma[x]=ma[x]==val[x]?x:(ma[x]==val[wma[ch[x][0]]]?wma[ch[x][0]]:wma[ch[x][1]]);
}
void reverse(int x)
{
	swap(ch[x][0],ch[x][1]);
	rev[x]^=1;
}
void Pushdown(int x)
{
	if(rev[x])
	{
		reverse(ch[x][0]);
		reverse(ch[x][1]);
		rev[x]=0;
	}
}
void down(int x)
{
	if(!rt[x])	down(fa[x]);
	Pushdown(x);
}
void Rotate(int x)
{
	int f=fa[x];
	bool k=which(x);
	if(rt[f])	rt[f]^=rt[x]^=1;
	else		ch[fa[f]][which(f)]=x;
	ch[f][k]=ch[x][!k];
	ch[x][!k]=f;
	fa[ch[f][k]]=f;
	fa[x]=fa[f];
	fa[f]=x;
	Pushup(f);
	Pushup(x);
}
void Splay(int x)
{
	down(x);
	while(!rt[x])
	{
		int f=fa[x];
		if(rt[f])
		{
			Rotate(x);
			return ;
		}
		if(which(x)^which(f))
			Rotate(x);
		else
			Rotate(f);
		Rotate(x);
	}
}
void access(int x)
{
	int y=0;
	while(x)
	{
		Splay(x);
		rt[ch[x][1]]=1,rt[y]=0;
		ch[x][1]=y;
		Pushup(x);
		y=x,x=fa[x];
	}
}
void Mtr(int x)
{
	access(x);
	Splay(x);
	reverse(x);
}
void Link(int x,int y)
{
	Mtr(x);
	fa[x]=y;
}
void Cut(int t,int x,int y)
{
	Mtr(t);
	access(x);
	Splay(t);
	rt[ch[t][1]]=1;
	fa[ch[t][1]]=0;
	ch[t][1]=0;
	access(y);
	Splay(t);
	rt[ch[t][1]]=1;
	fa[ch[t][1]]=0;
	ch[t][1]=0;
	Pushup(t);
}
int get_max(int x,int y)
{
	Mtr(x);
	access(y);
	Splay(x);
	return ma[x];
}
int get_wmax(int x,int y)
{
	Mtr(x);
	access(y);
	Splay(x);
	return wma[x];
}
int find(int x)
{
	return f[x]==x?x:find(f[x]);
}
void Build_Min_Tree(int n,int m)
{
	sort(total+1,total+m+1,cmp);
	for(int i=1;i<=n;i++)
		f[i]=i;
	int cnt=0;
	for(int i=1;i<=m;i++)
	{
		int x=find(total[i].x),y=find(total[i].y);
		if(x!=y)
		{
			f[x]=y;
			swap(total[i],total[++cnt]);
			if(cnt==n-1)
				break;
		}
	}
}
int main()
{
	int n,m,q,i,j,k,cnt1,cnt2,op,x,y,v;
	scanf("%d%d%d",&n,&m,&q);
	for(i=1;i<=m;i++)
	{
		total[i].x=read(),total[i].y=read(),total[i].val=read();
		if(total[i].x>total[i].y)
			swap(total[i].x,total[i].y);
	}
	sort(total+1,total+1+m);
	for(i=1,cnt1=cnt2=0;i<=q;i++)
	{
		op=read();
		if(op==1)
			Q[i].x=read(),Q[i].y=read(),Q[i].no=++cnt1;
		else
		{
			Q[i].op=1;
			Q[i].x=read(),Q[i].y=read();
			if(Q[i].x>Q[i].y)	swap(Q[i].x,Q[i].y);
			temp.x=Q[i].x,temp.y=Q[i].y;
			k=lower_bound(total+1,total+m+1,temp)-total;
			total[k].del=1,Q[i].val=total[k].val;
			Q[i].no=++cnt2;
		}
	}
	Build_Min_Tree(n,m);
	for(i=1;i<=n;i++)
		rt[i]=1,wma[i]=i;
	for(i=1;i<n;i++)
	{
		rt[i+n]=1,wma[i+n]=i+n,val[i+n]=ma[i+n]=total[i].val;
		Link(i+n,total[i].x);
		Link(i+n,total[i].y);
	}
	for(i=q;i>=1;i--)
	{
		if(Q[i].op)
		{
			x=Q[i].x,y=Q[i].y;
			rt[Q[i].no+(n<<1)]=1,wma[Q[i].no+(n<<1)]=Q[i].no+(n<<1);
			val[Q[i].no+(n<<1)]=ma[Q[i].no+(n<<1)]=Q[i].val;
			k=get_wmax(x,y);
			if(val[k]>Q[i].val)
			{
				Cut(k,x,y);
				Link(Q[i].no+(n<<1),x);
				Link(Q[i].no+(n<<1),y);
			}
		}
		else
		{
			ans[Q[i].no]=get_max(Q[i].x,Q[i].y);
		}
	}
	for(i=1;i<=cnt1;i++)
	{
		printf("%d\n",ans[i]);
	}
	return 0;
}
时间: 2024-08-29 22:28:15

bzoj-2594 水管局长数据加强版的相关文章

bzoj 2594: [Wc2006]水管局长数据加强版 动态树

2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec  Memory Limit: 128 MBSubmit: 934  Solved: 291[Submit][Status] Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径

【BZOJ 2594】 [Wc2006]水管局长数据加强版

2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec  Memory Limit: 128 MB Submit: 1138  Solved: 364 [Submit][Status] Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等

[bzoj2594][Wc2006]水管局长数据加强版

论蒟蒻的自我修养T_T.. 和noi2014魔法森林基本一样...然而数据范围大得sxbk...100w你告诉我(n+m)log(n+m)可过?[掀桌] 蒟蒻又蠢了..复杂度应该是O((n+q)log(n+m))吧.. 一开始数组开太小re了两发(要开到maxn+maxm),然后又开太大mle一发,然后无限tle...把记录类型全改成数组还是tle.... 最后把非lct部分改得和黄学长全部一样终于20+s卡过去了......... 然后发现自己原来是有个地方写萎了..一开始把没被删的边做kru

BZOJ 2594: [Wc2006]水管局长数据加强版(kruskal + LCT)

Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了.嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项. 在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗.消毒等等.嘟嘟在

BZOJ2594水管局长数据加强版

Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了.嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项. 在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗.消毒等等.嘟嘟在

BZOJ_2594_[Wc2006]水管局长数据加强版_LCT

Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了.嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项. 在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗.消毒等等.嘟嘟在

BZOJ 2594 Wc2006 水管局长数据加强版 Link-Cut-Tree

题目大意:给定一个无向图,多次删除某条边,多次查询两点之间路径上边权最大值的最小值 Link-Cut-Tree维护动态最小生成树 首先倒着做 将所有被删除的边标记(找边我用的排序+二分) 将没标记的边跑一遍Kruskal 求出最小生成树 然后每次加边和查询正常维护即可 LInk-Cut-Tree一气呵成写完,Kruskal尼玛写挂了-- 居然忘记把并查集连边 这我也是醉了 顺便吐槽一下题干上给的读入优化真尼玛弱--自己随便写一个都可以优化到RANK前十-- #include<cstdio> #

BZOJ 2594 [Wc2006]水管局长数据加强版 LCT

题意:链接 方法: LCT 解析: 搞了一个上午加1个小时的题,TM最后大错误居然是排序元素太多排不回原来的样子! 我要重新学排序! 这题是用LCT维护动态最小生成树,但是最小生成树上删边应该是做不到的,所以我们可以离线操作,之后先把所有该删的边删了然后倒着搞所有询问,这样删边就变成了加边,之后询问就是x到y路径上的最大边权. 图是动态的,所以想到LCT,但是LCT不能搞最大边权怎么办! 把每个边看做一个点. 假设这是第i个边,那么把他看做第i+n个点. 显然点权就是边权,然后将这个边连接的两个

【BZOJ 2594】【WC 2006】水管局长数据加强版

离线后倒过来做,这样就跟魔法森林差不多了,缩边为点就可以统计边的权值了. 1A真是爽,可惜常数炸上了天,这是滥用stl容器和无脑link,cut的后果 #include<map> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 100003; const int M = 1000003; void read(int &k

[BZOJ2594] [Wc2006]水管局长数据加强版(LCT + kruskal + 离线)

传送门 WC这个题真是丧心病狂啊,就是想学习一下怎么处理边权,给我来了这么一个破题! ORZ hzwer 临摹黄学长代码233 但还是复杂的一匹 理一下思路吧 题目大意:给定一个无向图,多次删除图中的某一条边,求两点间路径最大值的最小值 求两点间的路径最大值的最小值的话,可以求最小生成树,那么这个值就是最小生成树上两点间路径上的最大值 但是题目要求是删除边,LCT维护最小生成树不支持删边操作,那么就离线处理,倒着加边,用LCT维护. 就是这个离线处理是最恶心的. 来说说如何处理边权,把边也抽象成