• [IOI2018]狼人


    [IOI2018]狼人

    luogu
    UOJ
    对人形和狼形分别建克鲁斯卡尔重构树
    每次询问就是对于两棵树dfs序的一个二维数点,主席树维护

    #include<bits/stdc++.h>
    using namespace std;
    const int _=4e5+5;
    int re(){
        int x=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    int n,m,q,S,rt[_],s[_<<4],ls[_<<4],rs[_<<4];
    struct Edge{int u,v,w;}E[_];
    bool cmp1(Edge a,Edge b){return a.w>b.w;}
    bool cmp2(Edge a,Edge b){return a.w<b.w;}
    struct Kruskal_tree{
        int tot,cnt,ts;
        int fa[_],val[_],f[20][_],r[_],id[_],h[_],dfn[_];
        bool tag;
        struct edge{int to,next;}e[_];
        int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
        void link(int u,int v){e[++cnt]=(edge){v,h[u]};h[u]=cnt;}
        void dfs(int u){
            dfn[u]=++ts;id[ts]=u;
            for(int i=h[u];i;i=e[i].next)
                dfs(e[i].to);
            r[u]=ts;
        }
        void init(){
            tot=n;
            for(int i=1;i<=n<<1;i++)fa[i]=i;
            for(int i=1;i<=n;i++)val[i]=i;
            for(int i=1;i<=m;i++){//克鲁斯卡尔重构树
                int x=find(E[i].u),y=find(E[i].v);
                if(x==y)continue;
                val[++tot]=E[i].w;
                link(tot,x);link(tot,y);
                f[0][x]=f[0][y]=fa[x]=fa[y]=tot;
            }
            for(int i=1;i<=18;i++)//预处理倍增数组
                for(int j=1;j<=tot;j++)
                    f[i][j]=f[i-1][f[i-1][j]];
            dfs(tot);//预处理dfs序
        }
        int work(int x,int k){//倍增
            for(int i=18;i>=0;i--)
                if(f[i][x]&&((val[f[i][x]]>=k&&tag)||(!tag&&val[f[i][x]]<=k)))
                    x=f[i][x];
            return x;
        }
    }man,wolf;
    void upd(int&x,int l,int r,int k){
        s[++S]=s[x]+1;ls[S]=ls[x];rs[S]=rs[x];
        x=S;if(l==r)return;int mid=(l+r)>>1;
        if(k<=mid)upd(ls[x],l,mid,k);
        else upd(rs[x],mid+1,r,k);
    }
    int query(int x,int y,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr)return s[y]-s[x];
        int mid=(l+r)>>1,res=0;
        if(ql<=mid)res=query(ls[x],ls[y],l,mid,ql,qr);
        if(qr>mid)res+=query(rs[x],rs[y],mid+1,r,ql,qr);
        return res;
    }
    int main(){
        n=re(),m=re(),q=re();
        for(int i=1;i<=m;i++){
            E[i].u=re()+1,E[i].v=re()+1;
            E[i].w=min(E[i].u,E[i].v);
        }
        man.tag=1;
        sort(E+1,E+m+1,cmp1);
        man.init();
        for(int i=1;i<=m;i++)E[i].w=max(E[i].u,E[i].v);
        sort(E+1,E+m+1,cmp2);
        wolf.init();
        //预处理主席树
        for(int i=1;i<=man.tot;i++){
            rt[i]=rt[i-1];
            if(man.id[i]<=n)upd(rt[i],1,wolf.tot,wolf.dfn[man.id[i]]);
        }
        while(q--){
            int s=re()+1,t=re()+1,L=re()+1,R=re()+1;
            int A=man.work(s,L),B=wolf.work(t,R);
            if(query(rt[man.dfn[A]-1],rt[man.r[A]],1,wolf.tot,wolf.dfn[B],wolf.r[B]))puts("1");
            else puts("0");
        }
        return 0;
    }
    
  • 相关阅读:
    mysql数据库 --数据类型、约束条件
    并发编程 --线程
    并发编程 --进程
    MySQL数据库 --基础
    网络编程之 TCP-UDP的详细介绍
    网络编程之 OSI七层协议
    python 元类、单例模式
    python 面向对象_多态、内置方法、反射
    Python 面向对象_继承、组合
    简单工厂设计模式
  • 原文地址:https://www.cnblogs.com/sdzwyq/p/10038482.html
Copyright © 2020-2023  润新知