1. 程式人生 > >BZOJ1018:[SHOI2008]堵塞的交通

BZOJ1018:[SHOI2008]堵塞的交通

淺談樹狀陣列與線段樹:https://www.cnblogs.com/AKMer/p/9946944.html

題目傳送門:https://www.lydsy.com/JudgeOnline/problem.php?id=1018

我們把第一行和第二行的城市一起處理,對於每一個區間[\(l,r\)]的城市,我們需要維護下面六種關係:

一共六條邊,分別用\(bool\)型別的六個變數來表示這六種聯通關係是否成立。

然後詢問兩個城市是否聯通,也許他們會繞出區間[\(l,r\)]再繞回來然後聯通,所以有四種路徑可以走;假設我詢問的是一號城市和三號城市,二號城市是一號城市上方/下方的城市,四號城市是三號城市上方/下方的城市,那麼這四條路徑分別是:

一號---->三號(紅色)

一號----》二號---->三號(綠色)

一號---->四號----》三號(藍色)

一號----》二號---->四號----》三號(灰色)

其中>表示在區間內,》表示繞出去,如圖所示:

時間複雜度:\(O(nlong)\)

空間複雜度:\(O(n)\)

程式碼如下:

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn=1e5+5;

int n;
char s[10];
bool bo[maxn*3];//bo數組裡,[1,n-1]存的是第一行的道路,[n,2*n-1]存的是每一列的道路,[2*n,3*n-2]存的是第二行的道路。

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

struct tree_node {
    bool a1,a2,a3,a4,a5,a6;
};

struct segment_tree {
    tree_node tree[maxn<<2];

    tree_node merge(tree_node f,tree_node g,int mid) {
        tree_node res;int mid1=mid,mid2=mid+2*n-1;
        res.a1=(f.a1)|(f.a2&&bo[mid1]&&g.a1&&bo[mid2]&&f.a4);
        //f.a2&&bo[mid1]&&g.a1&&bo[mid2]&&f.a4  1號路徑
        //f.a5&&bo[mid2]&&g.a1&&bo[mid1]&&f.a6  2號路徑
        //如果2號路徑存在那麼1號路徑必然存在,所以只需要判1號路徑即可
        res.a2=(f.a2&&bo[mid1]&&g.a2)|(f.a5&&bo[mid2]&&g.a6);
        res.a3=(g.a3)|(g.a2&&bo[mid1]&&f.a3&&bo[mid2]&&g.a4);
        res.a4=(f.a4&&bo[mid2]&&g.a4)|(f.a6&&bo[mid1]&&g.a5);
        res.a5=(f.a2&&bo[mid1]&&g.a5)|(f.a5&&bo[mid2]&&g.a4);
        res.a6=(f.a4&&bo[mid2]&&g.a6)|(f.a6&&bo[mid1]&&g.a2);
        return res;
    }
    
    void build(int p,int l,int r) {
        if(l==r) {
            tree[p].a2=tree[p].a4=1;
            return;
        }
        int mid=(l+r)>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
    }
    
    void change(int p,int l,int r,int L,int R) {
        if(l==r) {
            if(L==R) {
                tree[p].a1^=1;
                tree[p].a3^=1;
                tree[p].a5^=1;
                tree[p].a6^=1;//如果是單點修改那麼這四種關係應該改變狀態
            }
            return;
        }
        int mid=(l+r)>>1;
        if(L<=mid)change(p<<1,l,mid,L,R);
        else change(p<<1|1,mid+1,r,L,R);
        tree[p]=merge(tree[p<<1],tree[p<<1|1],mid);     
    }

    tree_node query(int p,int l,int r,int L,int R) {
        if(L<=l&&r<=R)return tree[p];
        int mid=(l+r)>>1;tree_node res;
        if(R<=mid)res=query(p<<1,l,mid,L,R);
        else if(L>mid)res=query(p<<1|1,mid+1,r,L,R);
        else res=merge(query(p<<1,l,mid,L,R),query(p<<1|1,mid+1,r,L,R),mid);
        return res;
    }
}T;

int main() {
    n=read();T.build(1,1,n);
    while(~scanf("%s",s+1)) {
        if(s[1]=='E')break;
        int x1=read(),y1=read(),x2=read(),y2=read();
        if(y1>y2)swap(y1,y2),swap(x1,x2);
        if(s[1]=='O'||s[1]=='C') {
            if(x1==x2) {
                int tmp=y1;
                if(x1==2)tmp+=2*n-1;
                bo[tmp]^=1;T.change(1,1,n,y1,y2);
            }
            else {
                bo[y1+n-1]^=1;
                T.change(1,1,n,y1,y2);
            }
        }
        else {
            bool ans=0;
            tree_node j=T.query(1,1,n,1,y1);
            tree_node k=T.query(1,1,n,y1,y2);
            tree_node l=T.query(1,1,n,y2,n);
            if(x1==x2) {
                if(x1==1) {
                    ans|=k.a2;
                    ans|=j.a3&&k.a6;
                    ans|=k.a5&&l.a1;
                    ans|=j.a3&&k.a4&&l.a1;
                }
                else {
                    ans|=k.a4;
                    ans|=j.a3&&k.a5;
                    ans|=k.a6&&l.a1;
                    ans|=j.a3&&k.a2&&l.a1;
                }
            }
            else {
                if(x1==1) {
                    ans|=k.a5;
                    ans|=j.a3&&k.a4;
                    ans|=k.a2&&l.a1;
                    ans|=j.a3&&k.a6&&l.a1;
                }
                else {
                    ans|=k.a6;
                    ans|=j.a3&&k.a2;
                    ans|=k.a4&&l.a1;
                    ans|=j.a3&&k.a5&&l.a1;
                }
            }//對於詢問的兩個點的位置一共有四種不同的關係,分別分情況討論
            if(ans)puts("Y");
            else puts("N");
        }
    }
    return 0;
}