“蔚来杯“2022牛客暑期多校训练营9 C.Global Positioning System

原题链接

点击传送

题目大意

三维空间中有彼此相对静止的 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]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值