1. 程式人生 > >Luogu P4246 [SHOI2008]堵塞的交通(線段樹+模擬)

Luogu P4246 [SHOI2008]堵塞的交通(線段樹+模擬)

P4246 [SHOI2008]堵塞的交通

題意

題目描述

有一天,由於某種穿越現象作用,你來到了傳說中的小人國。小人國的佈局非常奇特,整個國家的交通系統可以被看成是一個\(2\)\(C\)列的矩形網格,網格上的每個點代表一個城市,相鄰的城市之間有一條道路,所以總共有\(2C\)個城市和\(3C-2\)條道路。

小人國的交通狀況非常槽糕。有的時候由於交通堵塞,兩座城市之間的道路會變得不連通,直到擁堵解決,道路才會恢復暢通。初來咋到的你決心毛遂自薦到交通部某份差事,部長聽說你來自一個科技高度發達的世界,喜出望外地要求你編寫一個查詢應答系統,以挽救已經病入膏肓的小人國交通系統。 小人國的交通部將提供一些交通訊息給你,你的任務是根據當前的交通情況回答查詢的問題。交通訊息可以分為以下幾種格式:

  • Close r1 c1 r2 c2:相鄰的兩座城市\((r_1, c_1)\)\((r_2, c_2)\)之間的道路被堵塞了;
  • Open r1 c1 r2 c2:相鄰的兩座城市\((r_1, c_1)\)\((r_2, c_2)\)之間的道路被疏通了;
  • Ask r1 c1 r2 c2:詢問城市\((r_1, c_1)\)\((r_2, c_2)\)是否連通。如果存在一條路徑使得這兩條城市連通,則返回Y,否則返回N

注:\(r_i\)表示行數,\(c_i\)表示列數, \(1\leq r_i\leq 2,1\leq c_i\leq C\)

輸入輸出格式

輸入格式:

第一行只有一個整數\(C\),表示網格的列數。接下來若干行,每行為一條交通訊息,以單獨的一行Exit作為結束。我們假設在一開始所有的道路都是堵塞的。我們保證\(C\)小於等於\(100000\),資訊條數小於等於\(100000\)

輸出格式:

對於每個查詢,輸出一個YN

輸入輸出樣例

輸入樣例#1:

2
Open 1 1 1 2
Open 1 2 2 2
Ask 1 1 2 2
Ask 2 1 2 2
Exit

輸出樣例#1:

Y
N

說明

資料範圍:

對於\(100\%\)的資料,\(1\leq C\leq 100000,1\leq \text{資訊條數}\leq 100000\)

思路

什麼**線段樹。 --Mercury

用線段樹來寫,每個結點維護區間\([l,r]\)的連通性。維護時記錄六個值:

  1. \(ldrd(left-down\ to\ right-down)\)
  2. \(luru(left-up\ to\ right-up)\)
  3. \(luld(left-up\ to\ left-down)\)
  4. \(rurd(right-up\ to\ right-down)\)
  5. \(lurd(left-up\ to\ right-down)\)
  6. \(ldru(left-down\ to\ right-up)\)

合併過程其實就是大力模擬的過程,考慮所有的路的經過情況。詳見程式碼的兩個update函式。

修改的時候要分類討論,橫線的變化與豎線的變化是不同的情況。

查詢的時候要注意,兩點可能繞外面的路互相到達,所以還是要大力模擬,考慮繞路和不繞路的情況。

程式碼的變數名還是比較清楚的,所以就詳見程式碼吧 (才不是我懶得寫)

AC程式碼

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
int n;
int ru[MAXN],rd[MAXN];
struct SegmentTree
{
    int l,r;
    bool ldrd,luru,luld,rurd,lurd,ldru;
    #define l(x) tree[x].l
    #define r(x) tree[x].r
    #define ldrd(x) tree[x].ldrd
    #define luru(x) tree[x].luru
    #define luld(x) tree[x].luld
    #define rurd(x) tree[x].rurd
    #define lurd(x) tree[x].lurd
    #define ldru(x) tree[x].ldru
}tree[MAXN<<2];
int read()
{
    int re=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
    return re;
}
char readc()
{
    char ch=getchar();
    while(!isalpha(ch)) ch=getchar();
    return ch;
}
void update(int p)
{
    l(p)=l(p<<1),r(p)=r(p<<1|1);
    ldrd(p)=(ldrd(p<<1)&&rd[r(p<<1)]&&ldrd(p<<1|1))||(ldru(p<<1)&&ru[r(p<<1)]&&lurd(p<<1|1));
    luru(p)=(luru(p<<1)&&ru[r(p<<1)]&&luru(p<<1|1))||(lurd(p<<1)&&rd[r(p<<1)]&&ldru(p<<1|1));
    luld(p)=luld(p<<1)||(luru(p<<1)&&ru[r(p<<1)]&&luld(p<<1|1)&&rd[r(p<<1)]&&ldrd(p<<1));
    rurd(p)=rurd(p<<1|1)||(luru(p<<1|1)&&ru[r(p<<1)]&&rurd(p<<1)&&rd[r(p<<1)]&&ldrd(p<<1|1));
    lurd(p)=(luru(p<<1)&&ru[r(p<<1)]&&lurd(p<<1|1))||(lurd(p<<1)&&rd[r(p<<1)]&&ldrd(p<<1|1));
    ldru(p)=(ldrd(p<<1)&&rd[r(p<<1)]&&ldru(p<<1|1))||(ldru(p<<1)&&ru[r(p<<1)]&&luru(p<<1|1));
}
void update(SegmentTree &re,SegmentTree x,SegmentTree y)
{
    re.l=x.l,re.r=y.r;
    re.ldrd=(x.ldrd&&rd[x.r]&&y.ldrd)||(x.ldru&&ru[x.r]&&y.lurd);
    re.luru=(x.luru&&ru[x.r]&&y.luru)||(x.lurd&&rd[x.r]&&y.ldru);
    re.luld=x.luld||(x.luru&&ru[x.r]&&y.luld&&rd[x.r]&&x.ldrd);
    re.rurd=y.rurd||(y.luru&&ru[x.r]&&x.rurd&&rd[x.r]&&y.ldrd);
    re.lurd=(x.luru&&ru[x.r]&&y.lurd)||(x.lurd&&rd[x.r]&&y.ldrd);
    re.ldru=(x.ldrd&&rd[x.r]&&y.ldru)||(x.ldru&&ru[x.r]&&y.luru);
}
void build(int p,int ll,int rr)
{
    if(ll==rr)
    {
        l(p)=ll,r(p)=rr;
        luru(p)=ldrd(p)=true;
        return ;
    }
    int mid=(ll+rr)>>1;
    build(p<<1,ll,mid);
    build(p<<1|1,mid+1,rr);
    update(p);
}
void change1(int p,int des,bool up,bool val)
{
    int mid=(l(p)+r(p))>>1;
    if(mid==des)
    {
        if(up) ru[des]=val;
        else rd[des]=val;
        update(p);
        return ;
    }
    if(des<=mid) change1(p<<1,des,up,val);
    else change1(p<<1|1,des,up,val);
    update(p);
}
void change2(int p,int des,bool val)
{
    if(l(p)==r(p))
    {
        luld(p)=rurd(p)=lurd(p)=ldru(p)=val;
        return ;
    }
    int mid=(l(p)+r(p))>>1;
    if(des<=mid) change2(p<<1,des,val);
    else change2(p<<1|1,des,val);
    update(p);
}
SegmentTree ask(int p,int ll,int rr)
{
    if(ll<=l(p)&&r(p)<=rr) return tree[p];
    int mid=(l(p)+r(p))>>1;
    if(rr<=mid) return ask(p<<1,ll,rr);
    else if(ll>mid) return ask(p<<1|1,ll,rr);
    else
    {
        SegmentTree re;
        update(re,ask(p<<1,ll,rr),ask(p<<1|1,ll,rr));
        return re;
    }
}
int main()
{
    n=read();
    build(1,1,n);
    while(true)
    {
        char opt=readc();
        if(opt=='E') break;
        int x=read(),y=read(),xx=read(),yy=read();
        if(y>yy) swap(x,xx),swap(y,yy);
        if(opt=='C')
        {
            if(y==yy) change2(1,y,false);
            else change1(1,y,x==1,false);
        }
        else if(opt=='O')
        {
            if(y==yy) change2(1,y,true);
            else change1(1,y,x==1,true);
        }
        else if(opt=='A')
        {
            SegmentTree ll=ask(1,1,y),mid=ask(1,y,yy),rr=ask(1,yy,n);
            if(x==1&&xx==1)
            {
                if(mid.luru||(ll.rurd&&mid.ldru)||(mid.lurd&&rr.luld)||(ll.rurd&&mid.ldrd&&rr.luld)) puts("Y");
                else puts("N");
            }
            else if(x==2&&xx==2)
            {
                if(mid.ldrd||(ll.rurd&&mid.lurd)||(mid.ldru&&rr.luld)||(ll.rurd&&mid.luru&&rr.luld)) puts("Y");
                else puts("N");
            }
            else if(x==1&&xx==2)
            {
                if(mid.lurd||(ll.rurd&&mid.ldrd)||(mid.luru&&rr.luld)||(ll.rurd&&mid.ldru&&rr.luld)) puts("Y");
                else puts("N");
            }
            else if(x==2&&xx==1)
            {
                if(mid.ldru||(ll.rurd&&mid.luru)||(mid.ldrd&&rr.luld)||(ll.rurd&&mid.lurd&&rr.luld)) puts("Y");
                else puts("N");
            }
        }
    }
    return 0;
}