Codechef :Push the Flow!/PUSHFLOW (树链剖分)

传送门

题解:
不错的树链剖分练习题。

又是毒瘤仙人掌,先把环缩起来,然后链剖维护重链上相邻的环的最小值。
对于轻边特殊处理,此时要对每个环再维护一个线段树。

时间复杂度 O ( n log ⁡ 2 n ) O(n \log^2 n) O(nlog2n)

#include <bits/stdc++.h>
using namespace std;
typedef pair <int,int> pii;
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=2e5+50, inf=2e9;
int n,m,k,scc,cnt;
int anc[N],vis[N],dep[N];
int id[N],bl[N],head[N],tail[N];
int fa[N],top[N],sze[N],son[N],st[N],ind;
struct edge {int x,y,w;} e[N];
map <int,int> Mp[N];
vector <int> gi[N];
struct ST {
	int mn[N*4];
	inline void inc(int k,int l,int r,int p,int v) {
		if(l==r) {mn[k]=v; return;}
		int mid=(l+r)>>1;
		(p<=mid) ? inc(k<<1,l,mid,p,v) : inc(k<<1|1,mid+1,r,p,v);
		mn[k]=min(mn[k<<1],mn[k<<1|1]); 
	}
	inline int ask(int k,int l,int r,int L,int R) {
		if(L<=l && r<=R) return mn[k]; 
		int mid=(l+r)>>1;
		if(R<=mid) return ask(k<<1,l,mid,L,R);
		else if(L>mid) return ask(k<<1|1,mid+1,r,L,R);
		else return min(ask(k<<1,l,mid,L,R),ask(k<<1|1,mid+1,r,L,R));
	}
	inline void inc(int pos,int v) {inc(1,1,n,pos,v);}
	inline int ask(int l,int r) {return (l>r) ? inf : ask(1,1,n,l,r);} 
} tree,chain,cir;
inline int ga(int x) {return (anc[x]==x) ? x : (anc[x]=ga(anc[x]));}
inline void add(int x,int y) {gi[x].push_back(y); gi[y].push_back(x);}
inline int lca(int x,int y) {
	while(top[x]^top[y]) (dep[top[x]]>dep[top[y]]) ? (x=fa[top[x]]) : (y=fa[top[y]]);
	return (dep[x]<dep[y]) ? x : y;
}
inline void dfs(int x,int f) {
	sze[x]=1; fa[x]=f; dep[x]=dep[f]+1;
	for(auto v:gi[x]) if(v^f) {
		dfs(v,x); sze[x]+=sze[v];
		if(sze[son[x]]<sze[v]) son[x]=v;
	}
}
inline void Dfs(int x,int f) {
	st[x]=++ind; top[x]=f; 
	if(son[x]) Dfs(son[x],f);
	for(auto v:gi[x]) if(v^fa[x] && v^son[x]) Dfs(v,v);
}
inline void work(int x,int y) {
	static int ql[N],qr[N]; ql[0]=qr[0]=0;
	while(x^y) (dep[x]<dep[y]) ? (qr[++qr[0]]=y, y=fa[y]) : (ql[++ql[0]]=x, x=fa[x]); ql[++ql[0]]=x;
	while(qr[0]) ql[++ql[0]]=qr[qr[0]--];
	++scc; head[scc]=cnt+1; tail[scc]=cnt+ql[0];
	for(int i=1;i<=ql[0];i++) id[ql[i]]=++cnt, bl[ql[i]]=scc; 
}
inline int calc(int a,int b) {
	if(a==b) return inf;
	if(id[a]>id[b]) swap(a,b);
	int mn1=cir.ask(id[a]+1,id[b]);
	int mn2=cir.ask(id[b]+1,tail[bl[b]]);
	mn2=min(mn2,cir.ask(head[bl[a]],id[a]));
	return min(INF,mn1+mn2;
}
inline void change(int i,int w) {
	if(bl[e[i].x]^bl[e[i].y]) {
		int x=(fa[bl[e[i].x]]==bl[e[i].y]) ? bl[e[i].x] : bl[e[i].y]; 
		tree.inc(st[x],w);
	} else {
		int x=e[i].x, y=e[i].y;
		if(id[x]>id[y]) swap(x,y);
		if(id[x]==id[y]-1) cir.inc(id[y],w);
		else cir.inc(id[x],w);
		if(fa[bl[x]] && son[bl[x]]) {
			int r=Mp[bl[x]][son[bl[x]]];
			int a=(bl[e[r].x]==bl[x]) ? e[r].x : e[r].y;
			r=Mp[bl[x]][fa[bl[x]]];
			int b=(bl[e[r].x]==bl[x]) ? e[r].x : e[r].y;
			chain.inc(st[bl[x]],calc(a,b));
		}
	}
}
inline void pre_calc() {
	for(int i=1;i<=scc;i++) 
	if(fa[i] && son[i]) {
		if(head[i]==tail[i]) chain.inc(st[i],inf);
	} else chain.inc(st[i],inf);
	for(int i=1;i<=m;i++) change(i,e[i].w); 
}
inline int ask_tree(int x,int f) {
	int ans=inf;
	while(top[x]^top[f]) ans=min(ans,tree.ask(st[top[x]],st[x])), x=fa[top[x]];
	if(x^f) ans=min(ans,tree.ask(st[son[f]],st[x]));
	return ans;
}
inline pii ask_cir(int last,int f) {
	int ans=inf;
	while(top[bl[last]]^top[f]) {
		int r=Mp[bl[last]][fa[bl[last]]];
		int a=(bl[e[r].x]==bl[last]) ? e[r].x : e[r].y;
		ans=min(ans,calc(last,a));
		ans=min(ans,chain.ask(st[top[bl[last]]],st[bl[last]]-1));
		r=Mp[top[bl[last]]][fa[top[bl[last]]]];
		last=(bl[e[r].x]==top[bl[last]]) ? e[r].y : e[r].x;
	}
	if(bl[last]^f) {
		int r=Mp[bl[last]][fa[bl[last]]];
		int a=(bl[e[r].x]==bl[last]) ? e[r].x : e[r].y;
		ans=min(ans,calc(last,a));
		ans=min(ans,chain.ask(st[f]+1,st[bl[last]]-1));
		r=Mp[son[f]][f];
		last=(bl[e[r].x]==f) ? e[r].x : e[r].y;
	} return pii(ans,last);
}
int main() {
	n=rd(), m=rd();
	for(int i=1;i<=n;i++) anc[i]=i;
	for(int i=1;i<=m;i++) e[i].x=rd(), e[i].y=rd(), e[i].w=rd();
	for(int i=1;i<=m;i++) if(ga(e[i].x)^ga(e[i].y)) {
		anc[ga(e[i].x)]=ga(e[i].y); vis[i]=1;
		add(e[i].x,e[i].y);
	} dfs(1,0);
	for(int i=1;i<=m;i++) if(!vis[i]) work(e[i].x,e[i].y);
	for(int i=1;i<=n;i++) if(!bl[i]) bl[i]=++scc, id[i]=++cnt;
	for(int i=1;i<=n;i++) gi[i].clear();
	for(int i=1;i<=m;i++) if(bl[e[i].x]^bl[e[i].y]) {
		Mp[bl[e[i].x]][bl[e[i].y]]=Mp[bl[e[i].y]][bl[e[i].x]]=i;
		add(bl[e[i].x],bl[e[i].y]);
	} 
	memset(sze,0,sizeof(sze)); memset(son,0,sizeof(son));
	dfs(1,0);  Dfs(1,1); 
	pre_calc(); k=rd();
	for(int i=1;i<=k;i++) {
		int op=rd(), x=rd(), y=rd();
		if(op==1) change(x,y);
		else {
			int l=lca(bl[x],bl[y]), ans=inf;
			ans=min(ans,min(ask_tree(bl[x],l),ask_tree(bl[y],l)));
			pii tx=ask_cir(x,l), ty=ask_cir(y,l);
			ans=min(ans,min(tx.first,ty.first));
			ans=min(ans,calc(tx.second,ty.second));
			printf("%d\n",ans);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值