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

匿名 (未验证) 提交于 2019-12-02 22:56:40
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/83010350

传送门

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

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

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

#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); 		} 	} } 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!