Tarjan

  • 有向图G中,以顶点v为起点的弧的数目称为v的出度,记做deg+(v);以顶点v为终点的弧的数目称为v的入度,记做deg-(v)。
  • 如果在有向图G中,有一条<u,v>有向道路,则v称为u可达的,或者说,从u可达v。
  • 什么是强连通?强连通其实就是指图中有两点u,v。使得能够找到有向路径从u到v并且也能够找到有向路径从v到u,则称u,v是强连通的。
  • 如果有向图G的任意两个顶点都互相可达,则称图 G是强连通图,如果有向图G存在两顶点u和v使得u不能到v,或者v不能到u,则称图G是强非连通图。

 

  • 如果有向图G不是强连通图,他的子图G2是强连通图,点v属于G2,任意包含v的强连通子图也是G2的子图,则乘G2是有向图G的极大强连通子图,也称强连通分量。

DFN【】记录遍历次序,low【】记录某环第一个被访问的点one,然后再第二次遍历到one的时候,将路径上所有的点的low【】全部更新为low【one】,也就是全部更新为第一次访问的点one;如果在回溯过程中DFN【X】 = low【X】,则说明存在一个强联通分量。

Tarjan:可以用来缩点和找环,> 将一个有向带环图变成了一个有向无环图(DAG图) <

【NOIP2015】信息传递

 数据规模与约定

测试点编号nn 的规模
1 n200n≤200
2
3
4 n2500n≤2500
5
6
7 n200000n≤200000
8
9
10

时间限制:1s

空间限制:128MB

 

#include <bits/stdc++.h>
using namespace std;
#define ll long long
using namespace std;
const int mod = 1e9+7;/// 998244353;
const int mxn = 2e5 +7;
int _,m,n,t,k,ans,cnt,lg;
vector<int>e[mxn];
stack<int>s;
int vis[mxn] , dfn[mxn] , low[mxn] ;
void tarjan(int x)
{
    vis[x] = 1 ; s.push(x);
    low[x] = dfn[x] = cnt++;
    for(int i=0 , v ;i<e[x].size();i++){
        v = e[x][i] ;
        if(!dfn[v]){
            tarjan(v);
            low[x] = min( low[x] , low[v] );
        } else {
            low[x] = min( low[x] , dfn[v] );
        }
    }
    if(dfn[x]==low[x]){
        int res = 0 ;
        while(1){
            int now = s.top(); s.pop();
            vis[now] = 0 ;
            res++;
            if(now==x) break;
        }
        if(res>1) ans = min(res , ans ) ;
    }
}
void solve()
{
    while(cin>>n)
    {
        cnt = 1 ; ans = mod ;
        for(int i=1;i<=n;i++){
            cin>>k;
            e[i].push_back(k);
        }
        for(int i=1;i<=n;i++){
            if(!vis[i]){
                tarjan(i);
            }
        }
        cout<< ans <<endl;
    }
}
int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    solve();
}
View Code

 

 HDU - 2586 How far away ?

There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.

InputFirst line is a single integer T(T<=10), indicating the number of test cases. 
  For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n. 
  Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.OutputFor each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.Sample Input

2
3 2
1 2 10
3 1 15
1 2
2 3

2 2
1 2 100
1 2
2 1

Sample Output

10
25
100
100
#include <bits/stdc++.h>
using namespace std;
#define ll long long
using namespace std;
const int mod = 1e9+7;/// 998244353;
const int mxn = 5e4 +7;
int _,m,n,t,k,ans,cnt,lg;
struct e{
    int to,x,nx;
}e[40000*2+7];
int dep[mxn] , f[mxn][30] , len[mxn] , head[mxn] ;
void add(int u,int v,int w)
{
    e[cnt].to = v;
    e[cnt].x = w ;
    e[cnt].nx = head[u];
    head[u] = cnt++;
}
void bfs()
{
    memset(f,0,sizeof(f));
    memset(dep,0.,sizeof(dep));
    queue<int>q;
    q.push(1);
    dep[1] = 1 ;
    while(!q.empty())
    {
        int u = q.front() ; q.pop() ;
        for(int i=head[u] ; ~i ;i = e[i].nx)
        {
            int v = e[i].to ;
            if(dep[v]) continue;
            len[v] = len[u] + e[i].x;
            dep[v] = dep[u] + 1 ;
            f[v][0] = u ; /// 存储父节点
            for(int j=1;j<=lg;j++)
                f[v][j] = f[ f[v][j-1] ][j-1] ;
            q.push(v);
        }
    }
}
int lca(int u,int v)
{
    if(dep[u]>dep[v] ) swap(u,v);
    for(int i=lg;i>=0;i--) /// 提升 V 和 U 至相同的高度
        if( dep[ f[v][i] ] >= dep[u] )
            v = f[v][i] ; 
    if(v==u) return u ;
    for(int i=lg;i>=0;i--) /// 找到最近的 LCA 
        if( f[u][i] != f[v][i] )
            u = f[u][i] , v = f[v][i] ;
    return f[u][0];
}
void solve()
{
    for(cin>>t;t;t--)
    {
        cin>>n>>m;
        cnt = 0 ; lg = int(log(n)/log(2))+1; 
        memset(head,-1,sizeof(head));
        for(int i=1,u,v,w;i<n;i++){
            cin>>u>>v>>w;
            add(u,v,w);
            add(v,u,w);
        }
        bfs();
        while(m--)
        {
            int u , v ;
            cin>>u>>v;
            cout<<len[u]+len[v] - 2*len[ lca(u,v) ]<<endl;
        }

    }
}
int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    solve();
}
View Code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
using namespace std;
const int mod = 1e9+7;/// 998244353;
const int mxn = 8e4 +7;
const int N = 8e4 + 7 ;
int _,m,n,t,k,ans,cnt,lg;
int head[N] , far[N] , len[N] , vis[N] , a[mxn] ;
vector< pair<int,int> > q[N] ; 
struct ${
    int to , nx , w ;    
}e[mxn*2];
int root(int x)
{
    return x==far[x] ? x : far[x] = root(far[x]);
}
void add(int u,int v,int w)
{
    e[cnt].to = v ;
    e[cnt].w = w ;
    e[cnt].nx = head[u] ;
    head[u] = cnt++;
}
void tarjan(int u)
{
    vis[u] = 1 ;
    for(int i=head[u];~i;i=e[i].nx){
        int v = e[i].to ;
        if(!vis[v]){
            len[v] = len[u] + e[i].w ;
            tarjan(v);
            far[v] = u ;    
        }
    }
    for(int i=0;i<q[u].size();i++){
        int v = q[u][i].first , id = q[u][i].second ;
        if(vis[v]==2){
            int lca = root(v);
            a[id] = min( a[id] , len[u]+len[v] - 2*len[lca] );
        }
    }
    vis[u] = 2 ; 
}
void init()
{
    cnt = 0 ;
    for(int i=0;i<=n;i++)
        len[i] = 0 , far[i] = i , vis[i] = 0;
    memset(head,-1,sizeof(head));
}
void solve()
{
    for(cin>>t;t;t--){ 
        cin>>n>>m; 
        init();
        for(int i=1,u,v,w;i<n;i++){
            cin>>u>>v>>w;
            add(u,v,w);
            add(v,u,w);
        }
        for(int i=1,u,v;i<=m;i++){
            cin>>u>>v;
            q[u].push_back( {v,i} );
            q[v].push_back( {u,i} );
            a[i] = 1<<30 ;
        }
        tarjan(1);
        for(int i=1;i<=m;i++)
            cout<<a[i]<<endl;
    }
}
int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    solve();
}
View Code

 

posted @ 2020-08-01 09:42  __MEET  阅读(130)  评论(0编辑  收藏  举报