带权并查集
以前对并查集刻板印象:这么削结构以达到优化目的的数据结构维护不了啥详细信息。
好吧,是可以的。
差分约束,带取模,考虑分 16 组带权并查集,每个点 \(p_i\) 存储其与父亲节点在模 \(2^k\) 下的差,压缩路径时是可以维护的。
CODE
#include<bits/stdc++.h>
#define fst first
#define sec second
#define mkp(a,b) make_pair(a,b)
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int maxn=5e5+5;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
x=(f ? -x : x);
}
void read(LL& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
x=(f ? -x : x);
}
struct DSU{
LL f[maxn],mod=0; LL val[maxn];
void init(int s){
for(int i=1;i<=s;i++) f[i]=i,val[i]=0;
}
int find_f(int u){
if(f[u]==u) return u;
int k=find_f(f[u]);
val[u]=val[u]+val[f[u]];
return f[u]=k;
}
void merge(int u,int v,LL p){
int ui=find_f(u),vi=find_f(v);
if(ui==vi) return;
f[vi]=ui,val[vi]=val[u]-val[v]-p;
}
bool check(int u,int v,LL p){
int ui=find_f(u),vi=find_f(v);
if(ui!=vi) return true;
return ((val[u]-val[v])%mod+mod)%mod==p;
}
}d[17];
int main(){
int n,m; read(n),read(m);
for(int i=0;i<17;i++) d[i].init(n),d[i].mod=(1<<i);
d[16].mod=0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=m;i++){
LL u,v,a,b; read(u),read(v),read(a),read(b);
int k=0; bool fg=1,spj=0;
if(b==-1) k=15,spj=1;
else k=log2(b);
if((1<<k)<b) ++k;
for(int j=0;j<=k;j++){
if(!d[j].check(u,v,a&(d[j].mod-1))){
fg=0; break;
}
}
if(spj&&(!d[16].check(u,v,a))){
fg=0;
}
if(!fg){
printf("0\n"); continue;
}
else{
printf("1\n");
}
for(int j=0;j<=k;j++){
d[j].merge(u,v,a&(d[j].mod-1));
}
if(spj) d[16].merge(u,v,a);
}
return 0;
}
//^o^

浙公网安备 33010602011771号