【CodeChef-PUSHFLOW】Push the Flow!(LCT)

传送门


看着提交记录中前面两位刚好是同机房神仙romiqi和Stargazer,一个RE一个WA,两个最后都选择了放弃,我非常忐忑地开了这道题

调了一上午,突然发现答案上界在2e9。。。

拿出第一次提交的代码,把INF设成2e9,然后发现2e9+1e9炸int了,define int long long,就过了。。。

所以我一上午调了个屁啊

然后改了改,把可能爆long long的地方开了long long,感觉还行。

题解:

简单LCT练习题

首先最大流=最小割,考虑求两点最小割。

如果是树上的话,显然就是两点之间边权的最小值。

由于是一个边仙人掌,我们发现在从一个点到另一个点割环的时候,环上最小的边可以考虑先强制割掉(如果能割掉的话),现在相当于环上其他的边的权值加上这条最小边的边权。

利用LCT 模拟 维护这个过程即可。

难写得一批树剖做法也难写得一批


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	template<typename T>
	inline T get(){
		char c;T num;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=1e5+7,M=2e5+7,INF=2e9+7;

int n,m,q;

struct edge{
	int u,v,w;
}e[M];
bool in_tree[M];

namespace LCT{
	cs int N=::N+::M;
	int fa[N],son[N][2],rev[N],mnp[N],cov[N],tag[N];
	ll mn[N],val[N],add[N];
	inline void pushup(int u){
		mn[u]=val[u],mnp[u]=u;
		if(son[u][0]&&mn[u]>mn[son[u][0]])mn[u]=mn[son[u][0]],mnp[u]=mnp[son[u][0]];
		if(son[u][1]&&mn[u]>mn[son[u][1]])mn[u]=mn[son[u][1]],mnp[u]=mnp[son[u][1]];
	}
	inline void pushadd(int u,ll v){val[u]+=v,add[u]+=v,mn[u]+=v;}
	inline void pushcov(int u,int v){cov[u]=v,tag[u]=v;}
	inline void pushdown(int u){
		if(rev[u]){
			std::swap(son[u][0],son[u][1]);
			if(son[u][0])rev[son[u][0]]^=1;
			if(son[u][1])rev[son[u][1]]^=1;
			rev[u]=0;
		}
		if(add[u]){
			if(son[u][0])pushadd(son[u][0],add[u]);
			if(son[u][1])pushadd(son[u][1],add[u]);
			add[u]=0;
		}
		if(tag[u]){
			if(son[u][0])pushcov(son[u][0],tag[u]);
			if(son[u][1])pushcov(son[u][1],tag[u]);
			tag[u]=0;
		}
	}
	inline bool isrt(int u){return son[fa[u]][0]!=u&&son[fa[u]][1]!=u;}
	inline bool which(int u){return son[fa[u]][1]==u;}
	inline void Rotate(int u){
		int p=fa[u],pp=fa[p],d=which(u);
		if(!isrt(p))son[pp][which(p)]=u;
		fa[u]=pp,fa[p]=u;if(son[u][!d])fa[son[u][!d]]=p;
		son[p][d]=son[u][!d],son[u][!d]=p;
		pushup(p),pushup(u);
	}
	inline void Splay(int u){
		static int q[N],qn;q[qn=1]=u;
		for(int re p=u;!isrt(p);p=fa[p])q[++qn]=fa[p];
		while(qn)pushdown(q[qn--]);
		for(int re p=fa[u];!isrt(u);Rotate(u),p=fa[u])
		if(!isrt(p))Rotate(which(u)==which(p)?p:u);
	}
	inline int access(int u){
		int ch=0;for(;u;u=fa[ch=u])
		Splay(u),son[u][1]=ch,pushup(u);
		return ch;
	}
	inline void makert(int u){
		rev[access(u)]^=1;Splay(u);
	}
	inline void select(int u,int v){
		makert(u),access(v);Splay(v);
	}
	inline int findrt(int u){
		for(u=access(u);pushdown(u),son[u][0];u=son[u][0]);
		Splay(u);return u;
	}
	inline bool con(int u,int v){
		makert(u);return findrt(v)==u;
	}
	inline void link(int u,int v){
		makert(u),fa[u]=v;
	}
	inline void cut(int u,int v){
		makert(u);access(v);Splay(v);
		son[v][0]=0,fa[u]=0,pushup(v);
	}
	inline void adde(int t){
		edge &e=::e[t];
		if(!con(e.u,e.v)){link(t,e.u);link(t,e.v);in_tree[t]=true;}
		else select(e.u,e.v),pushadd(e.v,e.w),pushcov(e.v,t),in_tree[t]=false;
	}
	inline void query(int u,int v){
		if(!con(u,v))cout<<"0\n";
		else select(u,v),cout<<mn[v]<<"\n";
	}
	inline void modify(){
		int t=gi(),nw=gi();
		if(!in_tree[t]){
			edge &e=::e[t];select(e.u,e.v);
			pushadd(e.v,nw-e.w);Splay(t);
			val[t]+=nw-e.w;e.w=nw;pushup(t);
		}else {
			edge &e=::e[t];Splay(t);
			val[t]+=nw-e.w;e.w=nw;
			pushup(t);t=cov[t];
		}
		if(!t)return ;
		select(e[t].u,e[t].v);
		int val=mn[e[t].v]-e[t].w;
		if(val>=e[t].w)return ;
		int p=mnp[e[t].v];
		pushadd(e[t].v,-e[t].w);
		in_tree[t]=true,in_tree[p]=false;
		cut(p,e[p].u),cut(p,e[p].v);
		link(t,e[t].u),link(t,e[t].v);
		select(e[p].u,e[p].v);
		pushadd(e[p].v,e[p].w);pushcov(e[p].v,p);
	}
}

int tp[M];
signed main(){
#ifdef zxyoi
	freopen("pushflow.in","r",stdin);
#endif
	n=gi(),m=gi();LCT::mn[0]=LCT::val[0]=INF;
	for(int re i=1;i<=m;++i){
		e[i].u=gi()+m;
		e[i].v=gi()+m;
		e[i].w=gi();tp[i]=i;
		LCT::val[i]=LCT::mn[i]=e[i].w;
	}
	for(int re i=1;i<=n;++i)LCT::val[i+m]=LCT::mn[i+m]=INF;
	for(int re i=1;i<=n+m;++i)LCT::mnp[i]=i;
	std::sort(tp+1,tp+m+1,[](int a,int b){return e[a].w>e[b].w;});
	for(int re i=1;i<=m;++i)LCT::adde(tp[i]);q=gi();
	while(q--){
		switch(gi()){
			case 0:LCT::query(gi()+m,gi()+m);break;
			case 1:LCT::modify();break;
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值