2022牛客多校 第9场 C Global Positioning System(讨论+lca+树上差分)
若干条路径生成了一个无向连通图,只有所有简单回路对应的向量为\(0\)向量时合法。
需要改变的边是满足这个边是所有不为\(0\)回路的交且不属于所有为\(0\)的回路。
因为题目满足一定有合法解,所以若存在不为\(0\)回路,上文所说的所有边都是答案。
若全部回路都为\(0\),所有割边都是答案。
具体的,就是先随便建出一棵生成树,然后对于非树边考虑其与树边构成的简单回路。然后讨论就可以了。
需要注意的是非树边的泰伦,因为满足一定存在合法解,若存在多个不为\(0\)的回路,非树边一定不为答案。若存在一个不为\(0\)回路,这个非树边一定为答案。(这个结论要考虑重合回路和非重合回路的多个回路)。
可以对图\(dfs\)求得生成树,每一条非树边就是返租边可以优化求\(lca\)的过程。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define int long long
const int N=5e5+550;
struct edge{
int to,nxt,x,y,z,id;
}e[N*2];
int cnt,head[N];
void add_edge(int u,int v,int x,int y,int z,int id){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
e[cnt].x=x;
e[cnt].y=y;
e[cnt].z=z;
e[cnt].id=id;
head[u]=cnt;
}
int sum[N][10];
int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return sum*f;
}
int f[N][22],dep[N];
void dfs(int u,int F){
f[u][0]=F;
dep[u]=dep[F]+1;
for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==F)continue;
sum[v][0]=sum[u][0]+e[i].x;
sum[v][1]=sum[u][1]+e[i].y;
sum[v][2]=sum[u][2]+e[i].z;
dfs(v,u);
}
}
int get_lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--)
if(dep[f[x][i]]>=dep[y])x=f[x][i];
if(x==y)return x;
for(int i=20;i>=0;i--)
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
struct qu_edge{
int u,v,x,y,z,id;
}qu_e[N];
int num,tmp;
int fa[N];
int find(int x){
if(x==fa[x])return x;
else return fa[x]=find(fa[x]);
}
int ans[N];
void get_ans(int u,int f,int type,int id){
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==f)continue;
get_ans(v,u,type,e[i].id);
sum[u][type]+=sum[v][type];
}
if(sum[u][type]==tmp&&id)ans[++ans[0]]=id;
}
signed main(){
int n=read(),m=read();
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++){
int u=read(),v=read();
int f_u=find(u),f_v=find(v);
int x=read(),y=read(),z=read();
if(f_u==f_v){
qu_e[++num].x=x;
qu_e[num].y=y;
qu_e[num].z=z;
qu_e[num].u=u;
qu_e[num].v=v;
qu_e[num].id=i;
}
else{
fa[f_u]=f_v;
add_edge(u,v,x,y,z,i);
add_edge(v,u,-x,-y,-z,i);
}
}
dfs(1,0);
tmp=0;
int e_id=0;
for(int i=1;i<=num;i++){
int u=qu_e[i].u,v=qu_e[i].v;
int lca=get_lca(u,v);
sum[u][4]++,sum[v][4]++;
sum[lca][4]-=2;
if(sum[u][0]-sum[v][0]==-qu_e[i].x&&sum[u][1]-sum[v][1]==-qu_e[i].y&&sum[u][2]-sum[v][2]==-qu_e[i].z){
sum[u][3]-=1e9;
sum[v][3]-=1e9;
sum[lca][3]+=2e9;
continue;
}
e_id=qu_e[i].id;
tmp++;
sum[u][3]++,sum[v][3]++;
sum[lca][3]-=2;
}
if(tmp==1)ans[++ans[0]]=e_id;
get_ans(1,0,3,0);
if(ans[0]==0)get_ans(1,0,4,0);
sort(ans+1,ans+1+ans[0]);
cout<<ans[0]<<endl;
for(int i=1;i<=ans[0];i++)cout<<ans[i]<<" ";
return 0;
}