zoukankan      html  css  js  c++  java
  • 圆方树学习笔记

    圆方树是什么

    对于一个无向图的每一个点双连通分量,都新建一个点,让这个点给点双连通分量的每一个点都连一个边。不考虑原来的边的话,此时图变成了一棵……不一定是树的东西,。我们令原来的点为圆点,新增的点为方点。这就是一棵圆方树。

    性质

    由上,可以发现圆方树的性质有:

    1. 树上任意一个边的两个点都不是同一种点。
    2. 方点的数量 = 点双连通分量的数量
    3. 每一个方点的度数 = 点双连通分量的点数

    实际应用

    例题1 P4630 【APIO2018】 Duathlon 铁人两项

    首先做一遍圆方树,我们发现对于每一个双连通分量而言,贡献的答案为siz-2siz为连通块大小)(两个点有一个都在内部好考虑,对于两个点有一个外面的就发现外面汇入到这里面来的时候会重,要-2)。我们再给圆方树的方点/圆点分别赋予权值(这也是很多圆方树题的重点)。我们发现当我们令方点权值为他的度数,圆点权值为-1的时候,则答案为经过的点的权值。

    朴素考虑两个点是(O(n^2))的,我们就对每个点考虑他对答案的贡献,然后就是套路dp(O(n)),发现瓶颈在Tarjan上,是(O(n+m))的,反正能过。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <cmath>
    namespace ztd{
        using namespace std;
        typedef long long ll;
    	const int mod = 998244353;
    	const int inf = 2147483647;
        template<typename T> inline T read(T& t) {//fast read
            t=0;short f=1;char ch=getchar();double d = 0.1;
            while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
            while (ch>='0'&&ch<='9') t=t*10+ch-'0',ch=getchar();
            if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
            t*=f;
            return t;
        }
    }
    using namespace ztd;
    const int maxn = 1e6+7, maxm = 4e6+7;
    int n, m, s, l, a[maxn];
    
    struct  Graph{
    	int last[maxn], gg[maxm], y[maxm], ecnt;
    	inline void addedge(int x, int yy){
    		y[++ecnt] = yy, gg[ecnt] = last[x];
    		last[x] = ecnt;
    	}
    	inline void clear(){
    		memset(last,0,sizeof(last));
    		memset(y,0,sizeof(y));
    		memset(gg,0,sizeof(gg)); 
    		ecnt = 0;
    	}
    }e, g;
    
    int siz[maxn];
    int totsiz, w[maxn];
    
    //***Tarjan************************************************************
    int dfx[maxn], low[maxn], dfxcnt, st[maxn], top, gtot;
    void Tarjan(int x){
    	dfx[x] = low[x] = ++dfxcnt; st[top++] = x; ++totsiz;
    	for(int i = e.last[x], y = e.y[i]; i; i = e.gg[i], y = e.y[i]){
    		if(!dfx[y]){
    			Tarjan(y);
    			low[x] = min(low[x], low[y]);
    			if(low[y] >= dfx[x]){
    				w[++gtot] = 0;
    				++gtot;
    				do{
    					g.addedge(st[--top], gtot); g.addedge(gtot, st[top]);
    					++w[gtot];
    				}while(st[top] ^ y);	
    				g.addedge(gtot, x); g.addedge(x, gtot); ++w[gtot];
    			}											
    		}else low[x] = min(low[x], dfx[y]);
    	}
    }
    //*********************************************************************
    ll ans;
    void dfs(int x, int fa){
    	siz[x] = (x <= n);
    	for(int i = g.last[x]; i; i = g.gg[i]){
    		int y = g.y[i]; 
    		if(y == fa) continue;
    		dfs(y, x);
    		ans += 2ll * w[x] * siz[x] * siz[y];
    		siz[x] += siz[y];
    	}	
    	ans += 2ll * w[x] * siz[x] * (totsiz-siz[x]);
    }
    
    signed main(){ 
    	gtot = read(n); read(m);
    	int xx, yy;
    	for(int i = 1; i <= n; ++i) w[i] = -1;
    	for(int i = 1; i <= m; ++i){
    		read(xx); read(yy); 
    		e.addedge(xx,yy); e.addedge(yy,xx);
    	}
    	for(int i = 1; i <= n; ++i){
    		if(!dfx[i]){
    			totsiz = 0;
    			Tarjan(i); --top;
    			dfs(i,0);
    		}
    	}
    	cout << ans << '
    ';
    	return 0;
    }
      
    
  • 相关阅读:
    《CLR via C#》笔记——运行时序列化(2)
    《CLR via C#》笔记——程序集的加载和反射(2)
    《CLR via C#》笔记——线程基础
    《CLR via C#》笔记——AppDomain(1)
    《CLR via C#》笔记——运行时序列化(1)
    《CLR via C#》笔记——程序集的加载和反射(3)
    《CLR via C#》笔记——AppDomain(2)
    C# 3.0 新特性概览
    【JAVASCRIPT】jquery实现新闻滚动效果
    【JAVASCRIPT】jquery实现图片笼罩效果
  • 原文地址:https://www.cnblogs.com/zimindaada/p/CircleSquareTree.html
Copyright © 2011-2022 走看看