牛客8 E Explorer 线段树分治

题意: n 个点 m 条双向边  每条双向边有一个上界 和一个下界   当     尺寸     下界<=(size)<=上界 时才可以通过   问有多少种尺寸可以从1 到n

#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define pb push_back
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
typedef pair<int,int>pii;
//////////////////////////////////
const int N=1e5+10;

vector<int>t[800000+10];
int l[N],r[N],b[2*N],u[N],v[N],n,m,nn;
#define lson l,m,pos<<1
#define rson m+1,r,pos<<1|1

void upsum(int L,int R,int id,int l,int r,int pos)
{
    if(L<=l&&r<=R) return (void)t[pos].push_back(id);
    int m=(l+r)>>1;
    if(L<=m)upsum(L,R,id,lson);
    if(R>m)upsum(L,R,id,rson);
}
int ans,f[N],x,y,siz[N];
int find1(int x)
{
    return f[x]==x?x:find1(f[x]);
}
void dfs(int l,int r,int pos)
{   
    vector<int>lastf;
    int m=(l+r)>>1;
    for(auto i:t[pos])
    {
        int x=find1(u[i]),y=find1(v[i]);
        if(x==y)continue;
        if(siz[x]>siz[y])swap(x,y);
        f[x]=y;lastf.push_back(x);
        siz[y]+=siz[x];
    }
    if(find1(1)==find1(n))ans+=b[r+1]-b[l];
    else if(l<r)dfs(lson),dfs(rson);
    for(auto i:lastf)f[i]=i;
    lastf.clear();
}
int main()
{
    scanf("%d%d",&n,&m);
    rep(i,1,n)f[i]=i,siz[i]=1;
    rep(i,1,m)
    {
        scanf("%d%d%d%d",&u[i],&v[i],&l[i],&r[i]);
        r[i]++;b[++nn]=l[i];b[++nn]=r[i];
    }
    sort(b+1,b+1+nn);
    nn=unique(b+1,b+1+nn)-b-1;
    rep(i,1,m)upsum(lower_bound(b+1,b+1+nn,l[i])-b,lower_bound(b+1,b+1+nn,r[i])-b-1,i,1,nn-1,1);
    dfs(1,nn-1,1);
    printf("%d\n",ans);
    return 0;
}
View Code

 注意size 改成左闭右开

猜你喜欢

转载自www.cnblogs.com/bxd123/p/11335569.html
今日推荐