• UOJ#416. 【APIO2018】铁人两项


    原文链接www.cnblogs.com/zhouzhendong/p/UOJ416.html

    前言

    完了完了SB选手Tarjan写挂。

    题解

    考虑先Tarjan缩个点双建个圆方树。

    然后发现,确定起点和终点后,中间点的可选方案数就是   这条路径上的所有点双 size 之和-2 。

    定义原点表示原图中的点,方点表示圆方树中新加入的点。

    这个东西可以转化为路径上的方点度数之和减去原点个数。

    定义点 x 的权值 d[x] ,当 x 为圆点时 d[x] = -1,否则 d[x] 等于 x 的度数。

    设起点终点都是圆点的经过点 x 的路径条数为 c[x],那么点 x 对答案的贡献就是 d[x] * c[x] 。

    时间复杂度 $O(n)$。

    代码

    #include <bits/stdc++.h>
    #define clr(x) memset(x,0,sizeof (x))
    #define For(i,a,b) for (int i=a;i<=b;i++)
    #define Fod(i,b,a) for (int i=b;i>=a;i--)
    #define pb(x) push_back(x)
    #define mp(x,y) make_pair(x,y)
    #define fi first
    #define se second
    #define real __zzd001
    #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
    #define outval(x) printf(#x" = %d
    ",x)
    #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
    #define outtag(x) puts("----------"#x"----------")
    #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);
    						For(_v2,L,R)printf("%d ",a[_v2]);puts("");
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector <int> vi;
    LL read(){
    	LL x=0,f=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		f|=ch=='-',ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return f?-x:x;
    }
    const int N=100005*2;
    int n,m,k;
    vector <int> e[N],t[N];
    LL ans=0;
    int dfn[N],low[N],st[N],Time=0,top=0;
    void Add_Edge(int x,int y){
    	t[x].pb(y),t[y].pb(x);
    }
    int Size;
    void Tarjan(int x){
    	Size++;
    	dfn[x]=low[x]=++Time;
    	st[++top]=x;
    	for (auto y : e[x])
    		if (!dfn[y]){
    			Tarjan(y);
    			low[x]=min(low[x],low[y]);
    			if (low[y]>=dfn[x]){
    				Add_Edge(x,++k);
    				do {
    					Add_Edge(st[top],k);
    				} while (st[top--]!=y);
    			}
    		}
    		else
    			low[x]=min(low[x],dfn[y]);
    }
    int size[N],d[N];
    void dfs(int x,int pre){
    	size[x]=x<=n;
    	int v=x<=n?-1:(int)t[x].size();
    	for (auto y : t[x])
    		if (y!=pre){
    			dfs(y,x);
    			ans+=2LL*v*size[x]*size[y];
    			size[x]+=size[y];
    		}
    	ans+=2LL*v*size[x]*(Size-size[x]);
    }
    int main(){
    	n=read(),m=read(),k=n;
    	For(i,1,m){
    		int x=read(),y=read();
    		e[x].pb(y),e[y].pb(x);
    	}
    	For(i,1,n)
    		if (!dfn[i])
    			Size=0,Tarjan(i),dfs(i,0);
    	cout<<ans<<endl;
    	return 0;
    }
    

      

  • 相关阅读:
    Java实现字符串的包含
    Java实现字符串的包含
    Java实现字符串的包含
    Java实现字符串的包含
    Java实现字符串的包含
    穷文富理撑死工,得先学门能挣钱的手艺
    Windows更新清理工具 (winsxs 清理工具)
    SQLite实现内存键值存储
    Qt5.7.0移植到4412
    罗辑思维2014 第11集 迷茫时代的明白人(慢慢来,能做一点是一点),有书卖
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ416.html
Copyright © 2020-2023  润新知