1. 程式人生 > >[Luogu4899][IOI2018] werewolf 狼人

[Luogu4899][IOI2018] werewolf 狼人

std esp clu == 區域 ont 題目 mbo res

luogu

sol

\(\mbox{IOI2018}\)的出題人有沒有看過\(\mbox{NOI2018}\)的題目呀。。。
\(\mbox{Kruskal}\)重構樹+二維數點。
題目相當於是問你從\(S\)出發只經過\(\ge L\)的點,和從\(T\)出發只經過\(\le R\)的點有沒有交集。
分別建兩棵最大/最小\(\mbox{Kruskal}\)重構樹,這樣從\(S\)出發,從\(T\)出發能到達的點就分別是兩棵樹上的一個子樹。以點在兩棵樹上的\(dfs\)序作為兩維坐標,每次詢問就是問你某個矩形區域裏面有沒有點。

code

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 4e5+5;
struct president_tree{int ls,rs,sz;}t[N*35];
int n,m,q,val[N],rt[N],tot;
vector<int>E[N];
struct Kruskal_rebuild_tree{
    int ty;
    int fa[N],nxt[N],hd[N],pa[20][N],dfn[N],low[N],tim;
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    void dfs(int u){
        dfn[u]=++tim;
        for (int j=1;j<20;++j) pa[j][u]=pa[j-1][pa[j-1][u]];
        for (int v=hd[u];v;v=nxt[v]) dfs(v);
        low[u]=tim;
    }
    void work(){
        for (int i=1;i<=n;++i) fa[i]=i;
        if (ty){
            for (int u=n;u;--u)
            for (int v:E[u])
                if (u<v){
                    v=find(v);if (u==v) continue;
                    nxt[v]=hd[u],hd[u]=v,fa[v]=pa[0][v]=u;
                }
            dfs(1);
        }else{
            for (int u=1;u<=n;++u)
            for (int v:E[u])
                if (u>v){
                    v=find(v);if (u==v) continue;
                    nxt[v]=hd[u],hd[u]=v,fa[v]=pa[0][v]=u;
                }
            dfs(n);
        }
    }
    int jump(int u,int k){
        for (int j=19;~j;--j)
            if (pa[j][u]&&((ty&&pa[j][u]>=k)||(!ty&&pa[j][u]<=k)))
                u=pa[j][u];
        return u;
    }
}A,B;
void modify(int &x,int l,int r,int p){
    t[++tot]=t[x];++t[x=tot].sz;
    if (l==r) return;int mid=l+r>>1;
    if (p<=mid) modify(t[x].ls,l,mid,p);
    else modify(t[x].rs,mid+1,r,p);
}
int query(int x,int y,int l,int r,int ql,int qr){
    if (l>=ql&&r<=qr) return t[x].sz-t[y].sz;
    int mid=l+r>>1,s=0;
    if (ql<=mid) s+=query(t[x].ls,t[y].ls,l,mid,ql,qr);
    if (qr>mid) s+=query(t[x].rs,t[y].rs,mid+1,r,ql,qr);
    return s;
}
int main(){
    n=gi();m=gi();q=gi();
    for (int i=1;i<=m;++i){
        int u=gi()+1,v=gi()+1;
        E[u].push_back(v);E[v].push_back(u);
    }
    A.ty=1;A.work();B.work();
    for (int i=1;i<=n;++i) val[A.dfn[i]]=B.dfn[i];
    for (int i=1;i<=n;++i) modify(rt[i]=rt[i-1],1,n,val[i]);
    while (q--){
        int s=gi()+1,e=gi()+1,l=gi()+1,r=gi()+1;
        s=A.jump(s,l);e=B.jump(e,r);
        puts(query(rt[A.low[s]],rt[A.dfn[s]-1],1,n,B.dfn[e],B.low[e])?"1":"0");
    }
    return 0;
}

[Luogu4899][IOI2018] werewolf 狼人