1. 程式人生 > >[BZOJ]1018 堵塞的交通(SHOI2008)

[BZOJ]1018 堵塞的交通(SHOI2008)

維護 inpu mage operator input 道路 rdquo char turn

  一道有點神的線段樹。

Description

  有一天,由於某種穿越現象作用,你來到了傳說中的小人國。小人國的布局非常奇特,整個國家的交通系統可以被看成是一個2行C列的矩形網格,網格上的每個點代表一個城市,相鄰的城市之間有一條道路,所以總共有2C個城市和3C-2條道路。 小人國的交通狀況非常槽糕。有的時候由於交通堵塞,兩座城市之間的道路會變得不連通,直到擁堵解決,道路才會恢復暢通。初來乍到的你決心毛遂自薦到交通部某份差事,部長聽說你來自一個科技高度發達的世界,喜出望外地要求你編寫一個查詢應答系統,以挽救已經病入膏肓的小人國交通系統。 小人國的交通部將提供一些交通信息給你,你的任務是根據當前的交通情況回答查詢的問題。交通信息可以分為以下幾種格式:

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

Input

  第一行只有一個整數C,表示網格的列數。接下來若幹行,每行為一條交通信息,以單獨的一行“Exit”作為結束。我們假設在一開始所有的道路都是堵塞的。

Output

  對於每個查詢,輸出一個“Y”或“N”。

Sample Input

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

Sample Output

  Y
  N

HINT

  C,信息條數<=100000。

Solution

  修改、詢問……首先確定這是一道數據結構題。

  可是它每次詢問的是兩個點的連通性,可持久化並查集?你在逗我?

  連通性怎麽維護?

  我們發現它實質上是在一條線段上進行連通性維護的,即使它有兩條,實際上是沒有太大區別的。

  我們仔細思考一下行數只有1的時候,用數據結構

怎麽做:

  用線段樹維護只在該區間影響下,區間兩端是否連通,合並起來是毫無壓力的。

  那麽行數為2的時候,我們也試試看這樣維護?

  我們用線段樹維護只在該區間影響下,區間中左上和右上右下,左下和右上右下是否連通,合並起來同樣也是沒有壓力的。

  這樣我們似乎就解決了詢問的問題?

  顯然這只是其中一種情況,但是還可能有區間外的邊影響其連通性的情況:

    技術分享

    技術分享

  當然還有更騷的,可以這樣:

    技術分享

  其實不外乎就是這4種情況,幸好我們都是可以處理的。

  你會發現後3種情況我們可以是看作幾個區間的共同作用:

    技術分享

    技術分享

  這樣你就突然發現,每個區間的作用是獨立的,也就是說正好是我們所能夠維護的。

  所以除了上面4項需要維護,我們還需要維護區間左上和左下是否連通,右上和右下是否連通,合並同樣很好實現。

  這樣我們就完美解決了詢問操作。

  至於修改操作根本就是小case了,小C也大約說一下自己的做法。

  更改不同行之間的連通性就是直接改。

  然而更改不同列之間的連通性可以動動腦子,我們可以預處理出第i列到第i+1列之間的道路哪個區間更新時會用到它。

  例如n=8,第4、5列之間的道路在[1,8]區間更新時被用到;第1、2列之間的道路在[1,2]區間更新時被用到。

  很容易證明列間道路和它的更新區間是一一對應的關系。

  所以修改某條列間道路時,只要順著線段樹往下找它對應的更新區間,做一次更新操作,再向上更新即可。

  時間復雜度O(nlogn*更新常數)。(不知道出題人總時間開3s是什麽心態……)

  (合並操作寫得像豆腐塊一樣)

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MN 100005
#define l(a) (a<<1)
#define r(a) (a<<1|1)
using namespace std;
const int zx[2][2]={{0,2},{3,1}};
int lk[3][MN];
struct node
{
    int r; bool a[6]; //--\/||
    friend node operator+(const node& a,const node& b)
    {
        node c;
        c.r=b.r;
        c.a[0]=a.a[0]&&lk[0][a.r]&&b.a[0]||a.a[2]&&lk[1][a.r]&&b.a[3];
        c.a[1]=a.a[1]&&lk[1][a.r]&&b.a[1]||a.a[3]&&lk[0][a.r]&&b.a[2];
        c.a[2]=a.a[0]&&lk[0][a.r]&&b.a[2]||a.a[2]&&lk[1][a.r]&&b.a[1];
        c.a[3]=a.a[1]&&lk[1][a.r]&&b.a[3]||a.a[3]&&lk[0][a.r]&&b.a[0];
        c.a[4]=a.a[4]||a.a[0]&&a.a[1]&&lk[0][a.r]&&lk[1][a.r]&&b.a[4];
        c.a[5]=b.a[5]||b.a[0]&&b.a[1]&&lk[0][a.r]&&lk[1][a.r]&&a.a[5];
        return c;
    }
}t[MN<<2];
int ct[MN][2];
int n;

inline int read()
{
    int n=0,f=1; char c=getchar();
    while (c<0 || c>9) {if(c==-)f=-1; c=getchar();}
    while (c>=0 && c<=9) {n=n*10+c-0; c=getchar();}
    return n*f;
}

node getitv(int x,int L,int R,int ql,int qr)
{
    if (ql==L&&qr==R) return t[x];
    int mid=L+R>>1;
    if (qr<=mid) return getitv(l(x),L,mid,ql,qr);
    else if (ql>mid) return getitv(r(x),mid+1,R,ql,qr);
    else return getitv(l(x),L,mid,ql,mid)+getitv(r(x),mid+1,R,mid+1,qr);
}
void getcg2(int x,int L,int R,int ql,int qr)
{
    if (ql==L&&qr==R) {t[x]=t[l(x)]+t[r(x)]; return;}
    int mid=L+R>>1;
    if (qr<=mid) getcg2(l(x),L,mid,ql,qr);
    else if (ql>mid) getcg2(r(x),mid+1,R,ql,qr);
    t[x]=t[l(x)]+t[r(x)];
}
void getcg1(int x,int L,int R,int q)
{
    if (L==R) {t[x].a[2]^=1; t[x].a[3]^=1; t[x].a[4]^=1; t[x].a[5]^=1; return;}
    int mid=L+R>>1;
    if (q<=mid) getcg1(l(x),L,mid,q); else getcg1(r(x),mid+1,R,q);
    t[x]=t[l(x)]+t[r(x)];
}

void build(int x,int L,int R)
{
    if (L==R) {t[x].r=R; t[x].a[0]=t[x].a[1]=true; return;}
    int mid=L+R>>1;
    ct[mid][0]=L; ct[mid][1]=R;
    build(l(x),L,mid); build(r(x),mid+1,R);
    t[x]=t[l(x)]+t[r(x)];
}

int main()
{
    register int x1,y1,x2,y2,g;
    char c[10];
    n=read();
    build(1,1,n);
    for (scanf("%s",c);c[0]!=E;scanf("%s",c))
    {
        x1=read()-1; y1=read(); x2=read()-1; y2=read();
        if (c[0]==O||c[0]==C)
        {
            if (x1==x2) {g=x1; if (y1>y2) swap(y1,y2);} else g=2;
            if (lk[g][y1]^(c[0]==C)) continue;
            lk[g][y1]^=1;
            if (g==2) getcg1(1,1,n,y1); else getcg2(1,1,n,ct[y1][0],ct[y1][1]);
        }
        else if (c[0]==A)
        {
            if (y1>y2) swap(x1,x2),swap(y1,y2);
            node lt=getitv(1,1,n,y1,y2),lt1,lt2;
            if (lt.a[zx[x1][x2]]) {puts("Y"); continue;}
            if (y1>1) lt1=getitv(1,1,n,1,y1-1);
            if (y2<n) lt2=getitv(1,1,n,y2+1,n);
            if (y1>1&&lt.a[zx[!x1][x2]]) if (lk[0][y1-1]&&lk[1][y1-1]&&lt1.a[5]) {puts("Y"); continue;}
            if (y2<n&&lt.a[zx[x1][!x2]]) if (lk[0][y2  ]&&lk[1][y2  ]&&lt2.a[4]) {puts("Y"); continue;}
            if (y1>1&&y2<n&&lt.a[zx[!x1][!x2]])
                if (lk[0][y1-1]&&lk[1][y1-1]&&lt1.a[5]&&lk[0][y2  ]&&lk[1][y2  ]&&lt2.a[4]) {puts("Y"); continue;}
            puts("N");
        }
    }
}

Last Word

  小D當時就丟了一句“大力維護就好了啊”讓小C茅塞頓開……

  “初來乍到”、“毛遂自薦”、“喜出望外”、“病入膏肓”……出題人的語文水平還是值得肯定的。

[BZOJ]1018 堵塞的交通(SHOI2008)