tarjan学习笔记
首先了解几个概念:
- 强连通(strongly connected): 在一个有向图G里,设两个点 a b 发现,由a有一条路可以走到b,由b又有一条路可以走到a,我们就叫这两个顶点(a,b)强连通。
- 强连通图:在一个有向图G中, 如果每两个点都强连通,我们就叫这个图,强连通图。
- 强连通分量strongly connected components):在一个有向图G中,有一个子图,这个子图每2个点都满足强连通,我们就叫这个子图叫做 强连通分量 [分量:把一个向量分解成几个方向的向量的和,那些方向上的向量就叫做该向量(未分解前的向量)的分量]
tarjan是一个基于DFS(深搜)的算法,它可以遍历一张有向图。tarjan将每一个强连通分量作为搜索树上的一个子树。而这个有向图,就是一个完整的搜索树。
tarjan算法的两个重要的参数:
- dfn[] : 这个点的次序编号(也就是被搜索到的次序);
- 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;
}
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/15791891.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!