• [BZOJ5463][APIO2018]铁人两项:Tarjan+圆方树


    分析

    根据题目中的要求,从(s)出发前往(f)一定可以,并且只可能经过这两个结点所在的点双连通分量和它们之间的点双连通分量,因此切换点(c)只能从这些点中选取。

    建出圆方树后,因为圆方树上一条路径的两个端点(圆点)不能作为切换点,并且路径上其他的圆点都被两个路径上的点双连通分量所包含,可以发现,如果把方点的权值设为这个点双连通分量的(siz),圆点的权值设为(-1),那么圆方树上所有两个端点都是圆点的路径的权值和就是答案。这个问题可以通过考虑每个结点在多少条路径上来解决。

    时间复杂度为(O(n))

    代码

    #include <bits/stdc++.h>
    #define rin(i,a,b) for(register int i=(a);i<=(b);++i)
    #define irin(i,a,b) for(register int i=(a);i>=(b);--i)
    #define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
    typedef __int128 LL;
    using std::cin;
    using std::cout;
    using std::endl;
    
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    void write(LL x){
    	if(x/10) write(x/10);
    	putchar(x%10+'0');
    }
    
    void writeln(LL x){
    	write(x);
    	putchar('
    ');
    }
    
    const int MAXN=1e6+5;
    const int MAXM=2e6+5;
    
    int n,m,ecnt,head[MAXN<<1];
    int dfn[MAXN],low[MAXN],tot;
    int sta[MAXN],top;
    int cnt;
    int totsiz,siz[MAXN<<1];
    LL ans;
    bool vis[MAXN<<1];
    std::vector<int> vdcc[MAXN];
    
    struct Edge{
    	int to,nxt;
    }e[MAXM<<2];
    
    inline void add_edge(int bg,int ed){
    	++ecnt;
    	e[ecnt].to=ed;
    	e[ecnt].nxt=head[bg];
    	head[bg]=ecnt;
    }
    
    void tarjan(int x){
    	dfn[x]=low[x]=++tot;
    	sta[++top]=x;
    	trav(i,x){
    		int ver=e[i].to;
    		if(!dfn[ver]){
    			tarjan(ver);
    			low[x]=std::min(low[x],low[ver]);
    			if(low[ver]>=dfn[x]){
    				++cnt;int las=0;
    				vdcc[cnt].push_back(x);
    				while(las!=ver){
    					las=sta[top];
    					vdcc[cnt].push_back(sta[top]);
    					--top;
    				}
    			}
    		}
    		else low[x]=std::min(low[x],dfn[ver]);
    	}
    }
    
    int getsiz(int x,int pre){
    	int ret=0;
    	trav(i,x){
    		int ver=e[i].to;
    		if(ver==pre) continue;
    		ret+=getsiz(ver,x);
    	}
    	if(x<=n) ++ret;
    	return ret;
    }
    
    void dfs(int x,int pre){
    	vis[x]=true;
    	trav(i,x){
    		int ver=e[i].to;
    		if(ver==pre) continue;
    		dfs(ver,x);
    		if(x<=n) ans-=1ll*siz[ver]*siz[x]*2;
    		else ans+=1ll*siz[ver]*siz[x]*(LL)vdcc[x-n].size()*2;
    		siz[x]+=siz[ver];
    	}
    	if(x<=n) ans-=1ll*(siz[x]+1)*(totsiz-siz[x])*2-2,++siz[x];
    	else ans+=1ll*siz[x]*(totsiz-siz[x])*(LL)vdcc[x-n].size()*2;
    }
    
    int main(){
    	n=read(),m=read();
    	rin(i,1,m){
    		int u=read(),v=read();
    		add_edge(u,v);
    		add_edge(v,u);
    	}
    	rin(i,1,n){
    		if(dfn[i]) continue;
    		if(!head[i]){
    			vdcc[++cnt].push_back(i);
    			continue;
    		}
    		top=0;tarjan(i);
    	}
    	ecnt=0;memset(head,0,sizeof head);
    	rin(i,1,cnt){
    		rin(j,0,(int)vdcc[i].size()-1){
    			add_edge(n+i,vdcc[i][j]);
    			add_edge(vdcc[i][j],n+i);
    		}
    	}
    	rin(i,1,n){
    		if(vis[i]) continue;
    		totsiz=getsiz(i,0);
    		dfs(i,0);
    	}
    	writeln(ans);
    	return 0;
    }
    
  • 相关阅读:
    iPhone UIButton图标与文字间距设置【转】
    UIButton左边图片右边文字的做法
    UICollectionViewCell设置阴影
    ARC中__bridge, __bridge__transfer, __bridge_retained 关系
    NSFileHandle的用法(用于读写文件)
    自定义FrameWork
    IOS7 适配以及向下兼容问题
    IOS 7 UITableView cell lines不能靠左解决方法
    xml报错“cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element”
    《Effective Java》笔记 :(一)创建和销毁对象
  • 原文地址:https://www.cnblogs.com/ErkkiErkko/p/10371972.html
Copyright © 2020-2023  润新知