BZOJ 1018 堵塞的交通 线段树维护连通性

$ \Rightarrow $ 戳我进BZOJ原题

[SHOI2008]堵塞的交通traffic

Time Limit: 3 Sec $ \quad $ Memory Limit: 162 MB

 

Description

有一天,由于某种穿越现象作用,你来到了传说中的小人国。
小人国的布局非常奇特,整个国家的交通系统可以被看成是一个$ 2 $ 行 $ C $ 列的矩形网格,
网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有 $ 2 \times C $个城市和 $ 3 \times C−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≤ri≤2,1≤ci≤C1 \leq r_i \leq 2, 1 \leq c_i \leq C $ 。
 

Input

第一行只有一个整数 $ C $ ,表示网格的列数。
接下来若干行,每行为一条交通信息,以单独的一行Exit作为结束。我们假设在一开始所有的道路都是堵塞的。
我们保证 $ C $ 小于等于 $ 100000 $ ,信息条数小于等于 $ 100000 $ 。
 

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

题解:JudgeOnline/upload/201604/sol(4).rar
 

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 200005
inline int read() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
int n;
char opt[5];
struct tree{ bool e[3][3]; }t[N<<2];
int a[N<<2][2];
void build(int o,int l,int r){
    if(l==r){
        t[o].e[0][0]=t[o].e[1][1]=1;
        return;
    }
    int mid=l+r>>1;
    build(o<<1,l,mid); build(o<<1|1,mid+1,r);
}
void pushup(int o,int l,int r){
    if(l==r) return;
    int L=o<<1,R=o<<1|1,mid=l+r>>1;
    t[o].e[0][0] = (t[L].e[0][0] && t[R].e[0][0] && a[mid][0]) || (t[L].e[0][1] && t[R].e[1][0] && a[mid][1]);
    t[o].e[0][1] = (t[L].e[0][0] && t[R].e[0][1] && a[mid][0]) || (t[L].e[0][1] && t[R].e[1][1] && a[mid][1]);
    t[o].e[1][0] = (t[L].e[1][0] && t[R].e[0][0] && a[mid][0]) || (t[L].e[1][1] && t[R].e[1][0] && a[mid][1]);
    t[o].e[1][1] = (t[L].e[1][0] && t[R].e[0][1] && a[mid][0]) || (t[L].e[1][1] && t[R].e[1][1] && a[mid][1]);
    t[o].e[2][0] = t[L].e[2][0] || (t[o].e[0][1] && t[o].e[1][1]) || (t[o].e[0][0] && t[o].e[1][0]) || (t[o].e[0][0] && t[o].e[1][1] && t[R].e[2][1]) || (t[L].e[0][0] && t[L].e[1][1] && t[R].e[2][0] && a[mid][0] && a[mid][1]);
    t[o].e[2][1] = t[R].e[2][1] || (t[o].e[0][0] && t[o].e[0][1]) || (t[o].e[1][0] && t[o].e[1][1]) || (t[o].e[0][0] && t[o].e[1][1] && t[L].e[2][0]) || (t[R].e[0][0] && t[R].e[1][1] && t[L].e[2][1] && a[mid][0] && a[mid][1]);
}
void updata_row(int o,int l,int r,int x,int p){
    //p==1 : open   p==0 : close
    if(l==r){
        t[o].e[0][0]=t[o].e[1][1]=1;
        t[o].e[1][0]=t[o].e[0][1]=t[o].e[2][0]=t[o].e[2][1]=p;
        return;
    }
    int mid=l+r>>1;
    if(x>mid) updata_row(o<<1|1,mid+1,r,x,p);
    else updata_row(o<<1,l,mid,x,p);
    pushup(o,l,r);
}
void updata_column(int o,int l,int r,int x,int c,int p){
    //p==1 : open   p==0 : close
    if(l==r){
        a[x][c]=p;
        return;
    }
    int mid=l+r>>1;
    if(x>mid) updata_column(o<<1|1,mid+1,r,x,c,p);
    else updata_column(o<<1,l,mid,x,c,p);
    pushup(o,l,r);
}
void work(int c1,int r1,int c2,int r2,int p){
    //p==1 : open   p==0 : close
    if(c1==c2) updata_row(1,1,n,c1,p);
    else {
        if(c1>c2) swap(c1,c2);
        if( (!a[c1][r1] && p==1) || (a[c1][r1] && p==0) )
            updata_column(1,1,n,c1,r1,p);
    }
}
tree query_direct(int o,int l,int r,int L,int R){
    if(L==l&&r==R) return t[o];
    int mid=l+r>>1;
    if(L>mid) return query_direct(o<<1|1,mid+1,r,max(mid+1,L),R);
    else if(R<=mid) return query_direct(o<<1,l,mid,L,min(mid,R));
    else {
        tree res,tL,tR;
        tL=query_direct(o<<1,l,mid,L,min(mid,R));
        tR=query_direct(o<<1|1,mid+1,r,max(mid+1,L),R);
        res.e[0][0] = (tL.e[0][0] && tR.e[0][0] && a[mid][0]) || (tL.e[0][1] && tR.e[1][0] && a[mid][1]);
        res.e[0][1] = (tL.e[0][0] && tR.e[0][1] && a[mid][0]) || (tL.e[0][1] && tR.e[1][1] && a[mid][1]);
        res.e[1][0] = (tL.e[1][0] && tR.e[0][0] && a[mid][0]) || (tL.e[1][1] && tR.e[1][0] && a[mid][1]);
        res.e[1][1] = (tL.e[1][0] && tR.e[0][1] && a[mid][0]) || (tL.e[1][1] && tR.e[1][1] && a[mid][1]);
        res.e[2][0] = tL.e[2][0] || (res.e[0][1] && res.e[1][1]) || (res.e[0][0] && res.e[1][0]) || (res.e[0][0] && res.e[1][1] && tR.e[2][1]) || (tL.e[0][0] && tL.e[1][1] && tR.e[2][0] && a[mid][0] && a[mid][1]);
        res.e[2][1] = tR.e[2][1] || (res.e[0][0] && res.e[0][1]) || (res.e[1][0] && res.e[1][1]) || (res.e[0][0] && res.e[1][1] && tL.e[2][0]) || (tR.e[0][0] && tR.e[1][1] && tL.e[2][1] && a[mid][0] && a[mid][1]);
        return res;
    }
}
bool query(int c1,int r1,int c2,int r2){
    if(c1>c2){ 
        swap(c1,c2); 
        swap(r1,r2); 
    }
    tree tmp=query_direct(1,1,n,c1,c2);
    if(tmp.e[r1][r2]) return 1;
    tree L=query_direct(1,1,n,1,c1);
    tree R=query_direct(1,1,n,c2,n);
    if(L.e[2][1] && tmp.e[r1^1][r2]) return 1;
    if(R.e[2][0] && tmp.e[r1][r2^1]) return 1;
    if(L.e[2][1] && R.e[2][0] && tmp.e[r1^1][r2^1]) return 1;
    return 0;
}
int main(){
    n=read();
    build(1,1,n);
    while(1){
        scanf("%s",opt);
        if(opt[0]=='E') break;
        int r1,c1,r2,c2;
        r1=read()-1; c1=read(); r2=read()-1; c2=read();
        if(opt[0]=='O') work(c1,r1,c2,r2,1);
        if(opt[0]=='C') work(c1,r1,c2,r2,0);
        if(opt[0]=='A') query(c1,r1,c2,r2) ? puts("Y") : puts("N");
    }
    return 0;
}
posted @ 2018-09-17 17:47  PotremZ  阅读(...)  评论(... 编辑 收藏