原题链接
题目大意
三维空间中有彼此相对静止的
n
n
n 个点,有
m
m
m 条记录,第
i
i
i 条记录表示第
u
i
u_i
ui 个点与第
v
i
v_i
vi 个点的坐标差为
(
x
i
,
y
i
,
z
i
)
(x_i,y_i,z_i)
(xi,yi,zi)。
这些记录中,有恰好一条记录是错的,当且仅当将该条记录的坐标差修改为其他值后,所有记录相互匹配吻合。
题解
考虑以给出的信息建边,所建成的图中,能发现错误的记录肯定在一个环上,我们可以通过观察环的边权来人眼分辨是否错误,对于计算机而言,我们只需要从一点的两边通过,一边正边权,一边负边权,查看是否值为
0
0
0 即可。
在一个环中,我们按照dfs序进行建树,当且仅当一个点多指向已出现的点时找到一个环,我们将其暂放一边,改环的两个特殊节点为改变所连接的两个点,如果相加和不为
0
0
0 则该环内的信息都可能出错。考虑多个环重合,可以得出若两个环都出问题,则必然是重合部分出错,对此,我们可以进行容斥,用差分计算重边,并加入统计。
对于其他的桥边,我们不需要过多操作,找出是否强联通即可,用 Tarjan 算法处理即可。
参考代码
#include<bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
const int N=2e6+5;
struct node{
int a,b,c,d;
node(int A,int B,int C,int D):a(A),b(B),c(C),d(D){}
node(){};
};
node operator+(const node & a,const node & b)
{
return node(a.a+b.a,a.b+a.b,a.c+b.c,a.d+b.d);
}
bool operator==(const node & a,const node & b)
{
return a.a==b.a&&a.b==b.b&&a.c==b.c;
}
int dep[N],h[N],vis[N];
node st[N];
int v1[N],v2[N];
vector<pair<int,node > > v[N];
int n,m,tot,maxn;
vector<int> ans;
void dfs(int x,int y,node q,int t) //差分+Tarjan
{
vis[x]=1;
dep[x]=dep[y]+1;
h[x]=t;
st[x]=q;
for(int i=0;i<(int)v[x].size();i++)
{
int f=v[x][i].first;
pair<int,node> son=v[x][i];
if(f==y)
continue;
if(!vis[f])
{
dfs(f,x,q+son.second,son.second.d);
v1[x]+=v1[f],v2[x]+=v2[f];
}
else if(dep[son.first]<dep[x]) //环
{
node o=q+son.second;
if(o==st[son.first])
{
v1[son.first]--; //差分操作
v1[x]++;
}
else
{
v2[son.first]--;
v2[x]++;
tot=son.second.d;
}
}
}
}
signed main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b,c,d,e;
scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e);
v[a].push_back(make_pair(b,node(c,d,e,i)));
v[b].push_back(make_pair(a,node(-c,-d,-e,i)));
}
dfs(1,0,node(0,0,0,0),0);
for(int i=1;i<=n;i++)
maxn=max(maxn,v2[i]);
for(int i=1;i<=n;i++) //第一条边不需要记录
if(v2[i]==maxn && !v1[i] && i!=1) //and 当差分值为maxn时为重叠部分->可能出错
ans.push_back(h[i]);
if(maxn==1)
ans.push_back(tot);
sort(ans.begin(),ans.end());
cout<<ans.size()<<endl;
for(int i=0;i<ans.size();i++)
printf("%lld ",ans[i]);
}