吊打全世界 - kruskal重构树 - 主席树 - 倍增

标题不是我起的不要D我惹
题目大意:给张无向图,多次询问是否存在从s到t的路径满足前半段路程点编号<=l,后半段点的编号>=r。
题解:一句话题解:分别建出kruskal重构树后二维数点即可。
(还有一个LCT做法并不想说)
(卡常使我快乐)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#define gc getchar()
#define pb push_back
#define N 200010
#define LOG 20
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef int arr[N];
vector<int> to[N],gl[N],gr[N];int upl[N][LOG],upr[N][LOG];
arr inl,outl,inr,outr,dl,dr,a,fa,Log,upds;int dfc;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
inline int cmpl(int x,int y) { return x<=y; }//x is zx of y
inline int cmpr(int x,int y) { return x>=y; }//x is zx of y
inline int findf(int x) { return (x==fa[x])?x:(fa[x]=findf(fa[x])); }
inline int kruskal(int n,int m,int *a,int *d,int (*up)[LOG],vector<int> *g,int (*cmp)(int,int))
{
    rep(i,1,n) fa[i]=i;
    for(int i=1,x,y,fy;i<=n;i++) if(to[x=a[i]].size())
        rep(j,0,(int)to[x].size()-1) if(cmp(x,y=to[x][j]))
            if(x^(fy=findf(y))) fa[fy]=x,up[fy][0]=x,g[x].push_back(fy);
    for(int i=n;i;i--) d[a[i]]=d[up[a[i]][0]]+1;
    for(int i=n;i;i--) for(int j=1,x=a[i];up[x][j]=up[up[x][j-1]][j-1];j++);
    return 0;
}
int dfs(int x,vector<int> *g,int *in,int *out)
{   in[x]=++dfc;rep(i,0,(int)g[x].size()-1) dfs(g[x][i],g,in,out);return out[x]=dfc;    }
struct segment{
    int s;segment *ch[2];
}*T[N];
int build(segment* &rt,int l,int r)
{
    rt=new segment,rt->s=0;if(l==r) return 0;int mid=(l+r)/2;
    return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),0;
}
int update(segment* &x,segment* &y,int p,int l,int r)
{
    x=new segment,x->ch[0]=y->ch[0],x->ch[1]=y->ch[1],
    x->s=y->s+1;if(l==r) return 0;int mid=(l+r)>>1;
    if(p<=mid) return update(x->ch[0],y->ch[0],p,l,mid);
    else return update(x->ch[1],y->ch[1],p,mid+1,r);
}
int query(segment* &x,segment* &y,int s,int t,int l,int r)
{
    if(s<=l&&r<=t) return y->s-x->s;int ans=0,mid=(l+r)>>1;if(y->s-x->s==r-l+1) return 1;
    if(s<=mid&&y->ch[0]->s-x->ch[0]->s) ans+=query(x->ch[0],y->ch[0],s,t,l,mid);if(ans) return 1;
    if(mid<t&&y->ch[1]->s-x->ch[1]->s) ans+=query(x->ch[1],y->ch[1],s,t,mid+1,r);return ans;
}
int get_zx(int x,int *d,int (*up)[LOG],int v,int (*cmp)(int,int))
{
    for(int i=Log[d[x]];i>=0;i--)
        if(up[x][i]&&cmp(v,up[x][i])) x=up[x][i];
    return x;
}
int main()
{
    int n=inn(),m=inn(),q=inn(),u,v;
    rep(i,2,n) Log[i]=Log[i>>1]+1;
    rep(i,1,m) u=inn(),v=inn(),to[u].pb(v),to[v].pb(u);
    rep(i,1,n) a[i]=n-i+1;kruskal(n,m,a,dl,upl,gl,cmpl);
    rep(i,1,n) a[i]=i;kruskal(n,m,a,dr,upr,gr,cmpr);
    dfc=0,dfs(1,gl,inl,outl),dfc=0,dfs(n,gr,inr,outr);
    rep(i,1,n) upds[inl[i]]=inr[i];build(T[0],1,n);
    rep(i,1,n) update(T[i],T[i-1],upds[i],1,n);
    for(int i=1;i<=q;i++)
    {
        int x=inn(),y=inn(),l=inn(),r=inn(),xs;
        if(x<l||y>r) { printf("N0\n");continue; }
        xs=x,x=get_zx(x,dl,upl,l,cmpl);
        if(inl[y]>=inl[x]&&inl[y]<=outl[x]) { printf("YE5\n");continue; }
        y=get_zx(y,dr,upr,r,cmpr);
        if(inr[xs]>=inr[y]&&inr[xs]<=outr[y]) { printf("YE5\n");continue; }
        if(query(T[inl[x]-1],T[outl[x]],inr[y],outr[y],1,n)) printf("YE5\n");
        else printf("N0\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值