#圆方树# [ssloj1492] [bzoj 2125]迷宫花坛(garden)

Title

#圆方树# [ssloj1492] [bzoj 2125]迷宫花坛(garden)_第1张图片


Solution

  1. 注意会有重边,求 d i s dis dis的时候注意要取最小值
  2. 此题数据较大,需要快读和快输,不然会 T L E TLE TLE

Code

#include
#define rr register 
#define ll long long 
#define rep(i,x,y) for(register ll i=x;i<=y;i++)
using namespace std; 
const ll N=200011; 
const ll M=500011;
ll ext; 
ll ans; 
ll n,m,R=1,Q; 
ll seg[N],rev[M],size[N],son[N],top[N],dep[N],TOT; 
ll father[N],tot; 
ll first[M],next[M],go[M],dis[N],d[M]; 
inline ll mymin(ll x,ll y){
	return x<y?x:y;
}
inline void myswap(ll &x,ll &y){
	ll t; t=x; x=y; y=t; return;
}
inline void in_add(rr ll x,rr ll y,rr ll z){
	next[++tot]=first[x],first[x]=tot,go[tot]=y,d[tot]=z;
}
inline void insert(rr ll x,rr ll y,rr ll z){
	in_add(x,y,z); in_add(y,x,z);
}
inline ll get(){
    rr char c; rr ll sign=1; 
    while ((c=getchar())<'0'||c>'9') if (c=='-') sign=-1; rr ll res=c-'0'; 
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0'; 
    return res*sign; 
}
inline void write(rr ll x){
	if (x>9) write(x/10); putchar(x%10+48);
}
inline void dfs1(rr ll u,rr ll f){
    rr ll e,v; 
    size[u]=1; 
    father[u]=f; 
    dep[u]=dep[f]+1; 
    for(e=first[u];v=go[e],e;e=next[e])
        if (v!=f){
        	if (!dis[v]) dis[v]=dis[u]+d[e]; else dis[v]=mymin(dis[v],dis[u]+d[e]); 
            dfs1(v,u); 
            size[u]+=size[v]; 
            if (size[v]>size[son[u]]) son[u]=v; 
        }   
    return;                                
}                  
inline void dfs2(ll u,ll linp){
	rr ll e,v;
	seg[u]=++seg[0],rev[seg[0]]=u,top[u]=linp;
	if (!son[u]) return; 
	dfs2(son[u],linp);
	for(e=first[u],v;v=go[e],e;e=next[e])
		if (v!=father[u]&&v!=son[u]) dfs2(v,v);
	return; 
}
inline ll lca(rr ll x,rr ll y){
    rr ll fx=top[x],fy=top[y]; 
    while(fx!=fy){
        if (dep[fx]<dep[fy]) myswap(x,y),myswap(fx,fy); 
        x=father[fx]; fx=top[x]; 
    }
    if (dep[x]>dep[y]) myswap(x,y); 
    return x;
}
ll dfn[N],low[N],cnt,b[N]; 
ll sum[N]; 
void square_point(ll u,ll v,ll w){
	++ext; 
	ll pre=w,i=v,P; 
	while (i!=father[u]) 
		sum[i]=pre,pre+=b[i],i=father[i]; 
	sum[ext]=sum[u]; sum[u]=0; i=v; 
	while (i!=father[u]) 
		P=mymin(sum[i],sum[ext]-sum[i]),insert(ext,i,P),i=father[i]; 
	return;
}
struct node{
	int y,z,next; 
}A[M];
ll head[N]; 
inline void add(ll x,ll y,ll z){
	A[++TOT]=(node){y,z,head[x]}; head[x]=TOT;
}
void tarjan(ll u,ll f){
	dfn[u]=low[u]=++cnt; 
	for(ll i=head[u];i;i=A[i].next){
		ll y=A[i].y; 
		if (y==f) continue; 
		if (!dfn[y]){
			father[y]=u; b[y]=A[i].z; 
			tarjan(y,u); 
			low[u]=mymin(low[u],low[y]); 
		} else low[u]=mymin(low[u],dfn[y]); 
		if (low[y]<=dfn[u]) continue; 
		insert(u,y,A[i].z); 
	}
	for(ll i=head[u];i;i=A[i].next){
		ll y=A[i].y; 
		if (father[y]==u||dfn[y]<=dfn[u]) continue; 
		square_point(u,y,A[i].z); 
	}
}
inline ll find(ll u,ll f){
	ll res=0; 
	while (top[u]!=top[f]) res=top[u],u=father[top[u]]; 
	return u==f?res:son[f]; 
}
int main(){ 
    n=get(); m=get();  ext=n; 
    for(ll i=1,s1,s2,s3;i<=m;i++) s1=get(),s2=get(),s3=get(),add(s1,s2,s3),add(s2,s1,s3); 
    tarjan(1,0); 
    dfs1(R,0); dfs2(R,R); Q=get();
    while (Q--){
    	ll u=get(),v=get(),p=lca(u,v); 
    	if (p<=n) ans=dis[u]+dis[v]-(dis[p]<<1); 
    	else {
    		ll RA=find(u,p),RB=find(v,p); 
    		ans=dis[u]+dis[v]-dis[RA]-dis[RB]; 
    		if (sum[RA]<sum[RB]) myswap(RA,RB); 
    		ans+=mymin(sum[RA]-sum[RB],sum[p]+sum[RB]-sum[RA]); 
    	}
    	write(ans); putchar('\n');
    }
    return 0; 
}

你可能感兴趣的:(圆方树(仙人掌问题),树链剖分)