JZOJ-senior-3899. 【NOIP2014模拟】逻辑的连通性

来源:互联网 发布:linux 重置网络配置 编辑:程序博客网 时间:2024/06/05 08:39

3899. 【NOIP2014模拟】逻辑的连通性 (Standard IO)

Time Limits: 2000 ms Memory Limits: 262144 KB Detailed Limits
Goto ProblemSet

Description

假如有命题p 一定能推出命题q,则称p 是q 的充分条件,q 是p 的必要条件。
特别的,当p 既是q 的充分条件,又是q 的必要条件时,称p 和q 互为充要条件
现在有n 个命题,其中一些是另一些的充分条件。请问有多少对命题互为充要条件?

Input

第一行三个正整数n,m,分别表示命题数、已知关系数
接下来m 行,每行两个正整数p 和q,表示命题p 是命题q 的充分条件

Output

仅一行,一个整数,表示充要条件的对数

Sample Input

5 5
1 3
3 2
2 1
4 5
5 4

Sample Output

4
样例说明:
4 对充要条件分别是(1, 2)、(2, 3)、(1, 3)、(4, 5)

Data Constraint

对于10% 的数据,n <= 10;m <= 50
对于40% 的数据,n <= 500;m <= 1000
对于另外10% 的数据,数据中保证没有重边且m = n^2
对于100% 的数据,n<= 50000;m <= 600000

题目大意:给定一些命题,求这些命题两两在一个环中的对数。

解题思路:Tarjan模板

uses math;var    a,b:array[0..600001,1..2] of longint;    z,dfn,low:array[0..50001] of longint;    p,bz:array[0..50001] of boolean;    n,m,t,i:longint;    ans:int64;procedure qsort(i,j:longint);    var        l,r,mid:longint;    begin        l:=i;        r:=j;        mid:=a[(l+r) div 2,1];        repeat            while a[l,1]<mid do inc(l);            while a[r,1]>mid do dec(r);            if l<=r then                begin                    a[0]:=a[l];                    a[l]:=a[r];                    a[r]:=a[0];                    inc(l);                    dec(r);                end;        until l>r;        if l<j then qsort(l,j);        if i<r then qsort(i,r);    end;procedure tarjan(x:longint);    var        i,k:longint;    begin        inc(t);        dfn[x]:=t;        low[x]:=t;//dfn,low初始化,记录访问该点的真实时间dfn和最早时间low        inc(z[0]);        z[z[0]]:=x;//当前元素入栈        bz[x]:=true;        p[x]:=true;//bz标记这个点是否被访问过,p标记这个点是否在栈内        for i:=b[x,1] to b[x,2] do//枚举每一条边        if i<>0 then        begin            if bz[a[i,2]]=false then                begin                    tarjan(a[i,2]);//如果节点i未被访问过继续向下找                    low[x]:=min(low[x],low[a[i,2]]);                end            else if p[a[i,2]] then low[x]:=min(low[x],dfn[a[i,2]]);//如果节点i还在栈内        end;        if dfn[x]=low[x] then//如果x的最早访问时间等于其实际访问时间,则可把其视作回路的"始点"            begin                k:=0;//连通块长度                while (z[0]>0) and (z[z[0]]<>x) do//将由x直接或间接扩展出的点标记为同一连通块,标记访问后出栈                    begin                        p[z[0]]:=false;                        inc(k);                        dec(z[0]);                    end;                p[x]:=false;                inc(k);                dec(z[0]);                ans:=ans+(k-1)*k div 2;            end;//如果节点x是强连通分量的根,退栈直到x的前一个数据,记录这个强连通分量的数据    end;begin    readln(n,m);    for i:=1 to m do readln(a[i,1],a[i,2]);    qsort(1,m);    b[a[1,1],1]:=1;    for i:=2 to m do if a[i,1]<>a[i-1,1] then        begin            b[a[i-1,1],2]:=i-1;            b[a[i,1],1]:=i;        end;    b[a[m,1],2]:=m;//前向星    t:=0;    ans:=0;    for i:=1 to n do if bz[i]=false then tarjan(i);    writeln(ans);end.
2 0
原创粉丝点击