加载中…

返回上一页

tarjan学习笔记

首先了解几个概念:

  1. 强连通(strongly connected): 在一个有向图G里,设两个点 a b 发现,由a有一条路可以走到b,由b又有一条路可以走到a,我们就叫这两个顶点(a,b)强连通。
  2. 强连通图:在一个有向图G中, 如果每两个点都强连通,我们就叫这个图,强连通图。
  3. 强连通分量strongly connected components):在一个有向图G中,有一个子图,这个子图每2个点都满足强连通,我们就叫这个子图叫做 强连通分量 [分量:把一个向量分解成几个方向的向量的和,那些方向上的向量就叫做该向量(未分解前的向量)的分量]

tarjan是一个基于DFS(深搜)的算法,它可以遍历一张有向图。tarjan将每一个强连通分量作为搜索树上的一个子树。而这个有向图,就是一个完整的搜索树。

tarjan算法的两个重要的参数:

  1. dfn[] : 这个点的次序编号(也就是被搜索到的次序);
  2. low[] : 每个点在这颗树中最小的子树的根。



离散化:
时间复杂度为O(NlogN)

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500005;
int c[maxn],n;//存树状数组,n表示点数,从-1-开始“important"
int aa[maxn];//存离散化后的数组
class node
{
    public:
    int val,order;
};
node in[maxn];//存原始数据
//树状数组的3个函数
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int val)
{
    for(int i=x;i<=n;i+=lowbit(i))
    {
        c[i]+=val;
    }
}
int getsum(int x)
{
    int temp=0;
    for(int i=x;i>=1;i-=lowbit(i))
    {
        temp+=c[i];
    }
    return temp;// 这个函数就是求区间和了。。比如getSum(7)的话,就是求a[1]+a[2]+...a[7];
}
bool cmp(node a,node b)
{
    if(a.val==b.val) return a.order<b.order;
    return a.val<b.val;
}
int main()
{
    while(scanf("%d",&n)==1&&n)
    {
        for(int i=1;i<=n;i++) {scanf("%d",&in[i].val);in[i].order=i;}
        //离散化
        sort(in+1,in+n+1,cmp);
        for(int i=1;i<=n;i++) aa[in[i].order]=i; /*因为a[1].val是最小的,order是它的位置,所以b[a[1].order]=1最小,  
         最小的数变成1,第二小的变成2,如此类推从而达到离散化*/  
        //用树状数组求逆序数
        memset(c,0,sizeof(c));
        long long ans=0;
        for(int i=1;i<=n;i++)
        {
            update(aa[i],1); 这里很巧妙,每一次更新后,判断此数比左边的数小的数有多少
            ans+=i-getsum(aa[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

posted @ 2022-01-13 20:37  1Liu  阅读(13)  评论(0编辑  收藏  举报