假设最开始的起点,也就是上文说的c点,用k表示;
1.明确只有在理想是1的时候,才会进行点的传递,所以我们在建图的时候,把理想度为1的加入图中;(这里注意点一共1e5个,边达到了1e9个,这个时候我们就要进行离散化操作)
2.先判断no的情况:
(1).如果全为0的时候:如果0的点中存在一个起始点是 k的点,那么直接输出no即可
(2).1构成的图不是欧拉图的时候也输出no
(3).举个例子(如下)
4 1
1 1 0
1 1 0 起点k是1点,但是还转移到 1点的时候,那么还是0
1 1 0
1 1 13.其余的情况均为yes:
那么如何输出呢?
(1)这里我们先输出理想度是0的,与k值不相等的情况,这样理想度是0的只剩余与k值相等的情况了;
(2)然后进行dfs特判欧拉路径,这里采用的是有向图判断欧拉路径+剪枝的方法,将欧拉路径存到栈中
(3)我们在对于栈中的路径,边输出便判断他是否转移的时候不是k,如果找到转移的点不是k的情况,我们就把理想度为0的起始点是k的全部输出掉;
(4)因为要输出yes和no,在第三步还要判断是否找到转移的点是不是k,所以(1),(2),(3)的输出暂时存入队列中。
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
const int N = 5e5 + 10;
const int INF = 0x3f3f3f3f;
const long long LLINF = 4e18 + 5;
typedef long long LL;
typedef pair<int, int> PII;
#define xx first
#define yy second
#define endl '\n'
struct node
{
// bool operator<(const node &a) const
// {
// }
};
void ClearFloat()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
}
int read()
{
int ret = 0, f = 1;
char ch = getchar();
while ('0' > ch || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while ('0' <= ch && ch <= '9')
{
ret = ret * 10 + ch - '0';
ch = getchar();
}
return ret * f;
}
int n, k, idx;
vector<PII> v[N]; // 存初始点->终点和所对应的边
map<int, vector<int>> mp; // 存理想都为0的起始点和边
int a[N], b[N], c[N], l[N]; // l是剪枝进行的
map<int, int> out, in, LOL, oo; // 统计入度,出度,进行离散化,栈中存的边转移后的点
bool flag; // 是不是全为0
queue<int> qe; // 暂时存答案
stack<int> sk; // 栈存欧拉图
void dfs(int u, int s)//dfs(点和边)
{
for (int i = l[u]; i < v[u].size(); i = l[u])
{
int pp = v[u][i].first;
if (pp)
{
v[u][i].first = 0;//剪枝
l[u]++;
dfs(pp, v[u][i].second);
}
}
//初始没有边只有遍历过的才有边
if (s != 0)
sk.push(s);
}
int main()
{
ClearFloat();
idx = 1;
cin >> n >> k;
for (int i = 1; i <= n; i++)
{
cin >> a[i] >> b[i] >> c[i];
// 进行离散化不然坐标高达1e9
if (!LOL.count(a[i]))
{
LOL[a[i]] = idx++;
}
if (!LOL.count(b[i]))
{
LOL[b[i]] = idx++;
}
// 建图
if (c[i])
{
flag = 1;
v[LOL[a[i]]].push_back({LOL[b[i]], i});
out[LOL[a[i]]]++; // 出度
in[LOL[b[i]]]++; // 入度
oo[i] = LOL[b[i]];
}
// 存理想度为0的边和起始点
else
mp[LOL[a[i]]].push_back(i);
}
// 全是0
if (flag == 0)
{
// k也要离散后的结果
k = LOL[k];
// 判断是不是有等于k值的
if (mp.count(k))
{
cout << "No" << endl;
}
// 没有直接输出
else
{
cout << "Yes" << endl;
for (auto it : mp)
{
for (auto u : it.second)
{
cout << u << " ";
}
}
}
}
else
{
// 离散的k值都没有说明没有起点
if (!LOL.count(k))
{
cout << "No" << endl;
}
else
{
k = LOL[k];
int sum1 = 0, sum2 = 0, root = k, s;
// 判断欧拉路径
for (int i = 1; i < idx; i++)
{
if (in[i] - out[i] > 1 || out[i] - in[i] > 1)
{
cout << "No" << endl;
return 0;
}
if (out[i] == in[i] + 1) // 起点
{
root = i;
s = v[i][0].second;
sum1++;
}
else if (out[i] == in[i] - 1)
{
sum2++;
}
}
if (sum1 > 1 || sum2 > 1)
{
cout << "No" << endl;
return 0;
}
else if (root != k)
{
cout << "No" << endl;
return 0;
}
// 把理想度是0但不等于k的输入到队列里
for (auto it : mp)
{
if (it.first != k)
{
for (auto u : it.second)
{
qe.push(u);
}
}
}
int ll = 0;
//进行欧拉路径操作
dfs(root, 0);
//栈中判断第三种no
while (sk.size())
{
qe.push(sk.top());
if (oo[sk.top()] != k && !ll)
{
ll = 1;
for (auto it : mp[k])
{
qe.push(it);
}
}
sk.pop();
}
//特判第(3)种no的情况
if (!ll)
{
cout << "No" << endl;
}
else
{
cout << "Yes" << endl;
while (qe.size())
{
cout << qe.front() << " ";
qe.pop();
}
}
}
}
}