「IOI2018」狼人

快咕一個月了ios

咕咕咕 咕咕咕咕git

LOJ #2865 Luogu P4899(離線)數組

UOJ #407(強制在線)less


題意

給定一棵樹和若干組詢問$(S,E,L,R)$spa

表示你初始在$S$,想到達$E$,有一次變身機會,變身前通過的點的編號不得小於$L$,變身後不得大於$R$code

判斷每組詢問是否可行blog

數據範圍差很少都是$2·10^5$get


 

題解

原問題等價於【從$ S$點出發不通過編號小於$ L$的點能到達的點集】和【從$ E$點出發不通過編號大於$ R$的點能到達的點集】是否有交string

維護一棵最大克魯斯卡爾重構樹和一棵最小克魯斯卡爾重構樹it

如今至關於每次詢問兩棵樹上各一棵子樹中是否編號集合有交

轉化成二維數點問題

即每一個點$ i$的座標都是$(dfn_1[i],dfn_2[i])$

每次詢問一個矩形中有沒有點

離線能夠樹狀數組掃描線水過

在線的話強上主席樹便可

時間複雜度$ O(Q ·\log n)$


代碼

這份是離線的

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define M 800010
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
    ll x=0;char zf=1;char ch=getchar();
    while(ch!='-'&&!isdigit(ch))ch=getchar();
    if(ch=='-')zf=-1,ch=getchar();
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*zf;
}
void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,ans,q;
struct ed{
    int x,y;
}e[M];
bool cmp1(ed x,ed y){
    return max(x.x,x.y)<max(y.x,y.y);
}
bool cmp2(ed x,ed y){
    return min(x.x,x.y)>min(y.x,y.y);
}
struct tree{
    int cnt,qwq;
    int F[M],L[M],N[M],a[M],fa[M],ff[M],val[M],dfn[M],id[M],size[M],up[M][20];
    int ask(int x){return (x==fa[x])?x:(fa[x]=ask(fa[x]));}
    void add(int x,int y){
        a[++k]=y;
        if(!F[x])F[x]=k;
        else N[L[x]]=k;
        L[x]=k;
    }
    int nomore(int x,int v){//包含x的通過邊權不超過val的重構樹上的點標號 
        for(rt i=18;i>=0;i--)if(val[up[x][i]]<=v&&up[x][i])x=up[x][i];
        return x;
    }
    int noless(int x,int v){//包含x的通過邊權很多於val的重構樹上的點標號 
        for(rt i=18;i>=0;i--)if(val[up[x][i]]>=v&&up[x][i])x=up[x][i];
        return x;
    }
    void init(){
        for(rt i=1;i<=cnt;i++)up[i][0]=ff[i];
        
        for(rt i=1;i<=18;i++)
        for(rt j=1;j<=cnt;j++)up[j][i]=up[up[j][i-1]][i-1];
    }
    void dfs(int x){
        dfn[x]=++qwq;id[qwq]=x;size[x]=1;
        for(rt i=F[x];i;i=N[i]){
            dfs(a[i]);
            size[x]+=size[a[i]];
        }
    }
}S1,S2;//<=x和>=x
struct query{
    int opt,pl,L,R,id;//opt:0點1,-1差分 
    bool operator <(const query s)const{
        if(pl==s.pl)return (bool)opt<(bool)s.opt; 
        return pl<s.pl;
    }
}a[M];
int anss[M],c[M];
void up(int x){
    for(rt i=x;i<=n*2;i+=i&-i)c[i]++;
}
int query(int x){
    int ret=0;
    for(rt i=x;i;i&=i-1)ret+=c[i];
    return ret;
}
int main(){
    n=read();m=read();q=read();
    for(rt i=0;i<m;i++){
        x=read()+1;y=read()+1;
        e[i]={x,y};
    }
    for(rt i=1;i<=2*n+1;i++)S1.fa[i]=S2.fa[i]=S1.ff[i]=S2.ff[i]=i;
    S1.cnt=S2.cnt=n;
    sort(e,e+m,cmp1);
    for(rt i=0;i<m;i++){
        int ls=S1.ask(e[i].x),rs=S1.ask(e[i].y);if(ls==rs)continue;
        S1.cnt++;S1.fa[S1.cnt]=S1.cnt;
        S1.fa[ls]=S1.fa[rs]=S1.ff[ls]=S1.ff[rs]=S1.cnt;S1.val[S1.cnt]=max(e[i].x,e[i].y);
        S1.add(S1.cnt,ls);S1.add(S1.cnt,rs);
    }
    sort(e,e+m,cmp2);
    for(rt i=0;i<m;i++){
        int ls=S2.ask(e[i].x),rs=S2.ask(e[i].y);if(ls==rs)continue;
        S2.cnt++;S2.fa[S2.cnt]=S2.cnt;
        S2.fa[ls]=S2.fa[rs]=S2.ff[ls]=S2.ff[rs]=S2.cnt;S2.val[S2.cnt]=min(e[i].x,e[i].y);
        S2.add(S2.cnt,ls);S2.add(S2.cnt,rs);
    }
    S1.dfs(S1.cnt);S2.dfs(S2.cnt);S1.init();S2.init();
    int t=0;
    for(rt i=1;i<=n;i++)a[++t]={0,S1.dfn[i],S2.dfn[i],0,0};
    for(rt i=0;i<q;i++){
        int S=read()+1,E=read()+1,L=read()+1,R=read()+1;
        int d2=S2.noless(S,L),d1=S1.nomore(E,R);
        a[++t]={-1,S1.dfn[d1]-1,S2.dfn[d2],S2.dfn[d2]+S2.size[d2]-1,i};
        a[++t]={1,S1.dfn[d1]+S1.size[d1]-1,S2.dfn[d2],S2.dfn[d2]+S2.size[d2]-1,i};
    }
    sort(a+1,a+t+1);
    for(rt i=1;i<=t;i++){
        if(a[i].opt==0)up(a[i].L);
        else anss[a[i].id]+=a[i].opt*(query(a[i].R)-query(a[i].L-1));
    }
    for(rt i=0;i<q;i++)writeln((bool)anss[i]);
    return 0;
}
相關文章
相關標籤/搜索