传送门
题意:给出一个无向图,每条边有一个size区间[l,r],代表可以通过人的大小,求可以从1到n,人的大小的方案数。
解:可以lct做,可是我还没学过lct。线段树+并查集的做法,我们先离散化size,使得线段树的节点代表size的一段区间,全部左开右闭(这样好处理)。然后我们将符合节点的边加进去,不需要下放。最后我们一遍深搜,深搜的同时将该节点的边,用并查集维护点之间的联通性,搜到叶子节点的时候,说明涵盖了这段区间的边都已经被加进去了,判断1和n的联通性,如果联通,那代表这段size的区间内的值都是可以使得1到n的,加上贡献。回溯的时候,我们将加的边撤销即可。
#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int maxn=1e5+5;
//il int Add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll x,int y) {return x*y>=mod?x*y%mod:x*y;}
int s[maxn<<2],n,m,ans=0;
vector<int> un[maxn<<3][2];
struct Collect{
int fa[maxn],rk[maxn];
void init(){
for(int i=0;i<maxn;++i) fa[i]=i,rk[i]=0;
}
int search(int x){
while(x^fa[x]) x=fa[x];
return x;
}
void unite(int x,int y,int rt){
x=search(x),y=search(y);
if(x==y) return ;
if(rk[x]>rk[y]){
fa[y]=x;
un[rt][1].pb(x),un[rt][0].pb(y); //father and son
}
else{
fa[x]=y;
if(rk[x]==rk[y]) rk[y]++;
un[rt][1].pb(y),un[rt][0].pb(x);
}
}
void reunite(int rt){
int len=SZ(un[rt][1]);
for(int i=0;i<len;++i){
rk[un[rt][1][i]]-=rk[un[rt][0][i]];
fa[un[rt][0][i]]=un[rt][0][i];
}
un[rt][1].clear(),un[rt][0].clear();
}
}co;
struct Tree {
struct node {
int l,r;
bool fg;
vector<int> v;
} sum[maxn<<3];
void build(int l,int r,int rt) {
if(l==r) {
sum[rt].fg=1;
sum[rt].l=s[l],sum[rt].r=s[l+1];
return ;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
sum[rt].l=sum[rt<<1].l,sum[rt].r=sum[rt<<1|1].r;
}
void update(int L,int R,int rt,int u,int v) {
if(L<=sum[rt].l && R>=sum[rt].r){
sum[rt].v.pb(u);
sum[rt].v.pb(v);
return ;
}
if(L<sum[rt<<1].r) update(L,R,rt<<1,u,v);
if(R>sum[rt<<1|1].l) update(L,R,rt<<1|1,u,v);
}
void over(int rt){
if(SZ(sum[rt].v)){
int len=SZ(sum[rt].v);
for(int i=0;i<len;i+=2){
co.unite(sum[rt].v[i],sum[rt].v[i+1],rt);
}
}
if(sum[rt].fg){
if(co.search(1)==co.search(n)){
ans+=sum[rt].r-sum[rt].l;
}
return ;
}
over(rt<<1);
co.reunite(rt<<1);
over(rt<<1|1);
co.reunite(rt<<1|1);
}
}tree;
int U[maxn],V[maxn],L[maxn],R[maxn];
int main() {
std::ios::sync_with_stdio(0);
scanf("%d%d",&n,&m);
int tot=0;
for(int i=1; i<=m; ++i) {
scanf("%d%d%d%d",&U[i],&V[i],&L[i],&R[i]);
s[++tot]=L[i],s[++tot]=(++R[i]);
}
sort(s+1,s+tot+1);
tot=unique(s+1,s+tot+1)-(s+1);
tree.build(1,tot-1,1);
co.init();
for(int i=1;i<=m;++i){
tree.update(L[i],R[i],1,U[i],V[i]);
}
tree.over(1);
printf("%d\n",ans);
return 0;
}