Loading

Codeforces Round #656 (Div. 3) E. Directing Edges(拓扑排序)

You are given a graph consisting of nn vertices and mm edges. It is not guaranteed that the given graph is connected. Some edges are already directed and you can't change their direction. Other edges are undirected and you have to choose some direction for all these edges.

You have to direct undirected edges in such a way that the resulting graph is directed and acyclic (i.e. the graph with all edges directed and having no directed cycles). Note that you have to direct all undirected edges.

You have to answer tt independent test cases.

Input

The first line of the input contains one integer tt (1≤t≤2⋅1041≤t≤2⋅104 ) — the number of test cases. Then tt test cases follow.

The first line of the test case contains two integers nn and mm (2≤n≤2⋅1052≤n≤2⋅105 , 1≤mmin(2⋅105,n(n−1)2)1≤m≤min(2⋅105,n(n−1)2) ) — the number of vertices and the number of edges in the graph, respectively.

The next mm lines describe edges of the graph. The ii -th edge is described with three integers titi , xixi and yiyi (ti∈[0;1]ti∈[0;1] , 1≤xi,yin1≤xi,yi≤n ) — the type of the edge (ti=0ti=0 if the edge is undirected and ti=1ti=1 if the edge is directed) and vertices this edge connects (the undirected edge connects vertices xixi and yiyi and directed edge is going from the vertex xixi to the vertex yiyi ). It is guaranteed that the graph do not contain self-loops (i.e. edges from the vertex to itself) and multiple edges (i.e. for each pair (xi,yixi,yi ) there are no other pairs (xi,yixi,yi ) or (yi,xiyi,xi )).

It is guaranteed that both sum nn and sum mm do not exceed 2⋅1052⋅105 (∑n≤2⋅105∑n≤2⋅105 ; ∑m≤2⋅105∑m≤2⋅105 ).

Output

For each test case print the answer — "NO" if it is impossible to direct undirected edges in such a way that the resulting graph is directed and acyclic, otherwise print "YES" on the first line and mm lines describing edges of the resulted directed acyclic graph (in any order). Note that you cannot change the direction of the already directed edges. If there are several answers, you can print any.

Example

Input

Copy

4

3 1

0 1 3

5 5

0 2 1

1 1 5

1 5 4

0 5 2

1 3 5

4 5

1 1 2

0 4 3

1 3 1

0 2 3

1 2 4

4 5

1 4 1

1 1 3

0 1 2

1 2 4

1 3 2

Output

Copy

YES

3 1

YES

2 1

1 5

5 4

2 5

3 5

YES

1 2

3 4

3 1

3 2

2 4

NO

 

据说是套路题由于不会套路+菜所以看出来了topo也不会做…这个题一开始的无向边其实并没有太多作用,全部存到vector里便于赋方向。关键是有向边。对有向的图(可能不连通)进行拓扑排序并得到一个拓扑序,如果出队次数不等于n的话说明有环,直接输出NO,否则的话遍历之前的无向边vector,对于每条边,规定方向为从拓扑序小的点到拓扑序大的点,这样一定能保证新图仍然是一个DAG。输出新的有向边和原来的有向边即可。注意:不要对无向边建边,这样会使拓扑排序时产生冗余的遍历,对于m=2e5,t全为0的数据会t QAQ

#include <bits/stdc++.h>
#define N 200005
using namespace std;
int n, m, head[N], ver[N], Next[N], edge[N], tot, deg[N], num[N];//deg为入度 
void add(int x, int y, int z) { ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot; }
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
struct Edge
{
    int x, y;
};
bool TopoSort()
{
    queue<int> q;
    for(int i = 1; i <= n; i++) 
        if(!deg[i]) q.push(i);
    int cnt = 0;
    while(q.size())
    {
        int x = q.front();
        q.pop();
        num[x] = ++cnt;
        for(int i = head[x]; i; i = Next[i])
        {
            int y = ver[i], z = edge[i];
            deg[y]--;
            if(!deg[y]) q.push(y);
        }
    }
    return cnt == n;
}
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        tot = 0;
        memset(head, 0 ,sizeof(head));//邻接表只需要初始化head和tot即可, 
        memset(deg, 0, sizeof(deg));
        vector<Edge> e1, e2;
        cin >> n >> m;
        for(int i = 1; i <= m; i++)
        {
            int t, x, y;
            t = read(), x = read(), y = read();
            if(t == 0)
            {
                //add(x, y, -1);
                //add(y, x, -1);
                //这里就不要加边了,加了也没有用,且拓扑排序的时候会额外访问到,导致T 
                e1.push_back(Edge{x, y});
            }
            else 
            {
                add(x, y, 1);
                e2.push_back(Edge{x, y});
                deg[y]++;
            }
        }
        if(!TopoSort()) cout << "NO" <<endl;
        else
        {
            cout << "YES" << endl;
            for(int i = 0; i < e1.size(); i++)
            {
                if(num[e1[i].x] < num[e1[i].y]) printf("%d %d\n", e1[i].x, e1[i].y);
                else printf("%d %d\n", e1[i].y, e1[i].x);
            }
            
            for(int i = 0; i < e2.size(); i++) printf("%d %d\n", e2[i].x, e2[i].y);
        }
        
    }
    return 0;
}
//NO:已经存在环 

 

posted @ 2020-07-19 01:46  脂环  阅读(403)  评论(2编辑  收藏  举报