[SHOI2008]堵塞的交通traffic

Posted Wolfycz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SHOI2008]堵塞的交通traffic相关的知识,希望对你有一定的参考价值。

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”作为结束。
我们假设在一开始所有的道路都是堵塞的。
我们保证 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

嗯,这题是一道线段树神题。线段树要维护一些信息,维护区间内左上左下,右上右下的连通情况,以及第一行和第二行是否可以向外延伸(共计$luru、lurd、luld、ldru、ldrd、rurd、road[0/1]$8条信息)。
那么我们维护这些信息有什么用呢?
技术分享图片
维护这个信息是为了区间合并用的。我们先画个图(如上图),我现在要将两个区间合并。
新的信息如何维护?
\(lu1\)-->\(ru2:lu1\)-->\(ru1\)+第一行连通+\(lu2\)-->\(ru2\)
\(lu1\)-->\(ru2:lu1\)-->\(rd1\)+第二行连通+\(ld2\)-->\(ru2\)
上面我列举了\(lu1\)-->\(ru2\)的情况,其他的7中情况都有类似的合并方式,我就不一一列举了,对这代码和图就能理解。
至于如何判断连通?同样对着代码和图理解下即可。
(ps:附上一图,以便check理解)
技术分享图片

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline 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<<1)+(x<<3)+ch-‘0‘;
    return x*f;
}
inline void print(int x){
    if (x>=10)     print(x/10);
    putchar(x%10+‘0‘);
}
const int N=1e5;
int n;
struct Segment{
    #define ls (p<<1)
    #define rs (p<<1|1)
    struct AC{
        bool luru,luld,lurd,ldru,rurd,ldrd;//6种连通方式
        bool road[2];
        void init(){luld=luru=ldru=rurd=0,luru=ldrd=1;}
        void add(bool flag){luld=rurd=lurd=ldru=flag;}
    }tree[N*4+10];
    AC updata(AC x,AC y){
        AC ans;
        ans.road[0]=y.road[0],ans.road[1]=y.road[1];//因为第一行和第二行的连通是互相的,所以找哪个都无所谓
        ans.luru=ans.luld=ans.lurd=ans.ldru=ans.rurd=ans.ldrd=0;
        if ((x.luru&&x.road[0]&&y.luru)||(x.lurd&&x.road[1]&&y.ldru))   ans.luru=1;
        if ((x.ldrd&&x.road[1]&&y.ldrd)||(x.ldru&&x.road[0]&&y.lurd))   ans.ldrd=1;
        if ((x.luru&&x.road[0]&&y.lurd)||(x.lurd&&x.road[1]&&y.ldrd))   ans.lurd=1;
        if ((x.ldrd&&x.road[1]&&y.ldru)||(x.ldru&&x.road[0]&&y.luru))   ans.ldru=1;
        if ((x.luld)||(x.luru&&x.road[0]&&y.luld&&x.road[1]&&x.ldrd))   ans.luld=1;
        if ((x.rurd&&x.road[0]&&y.luru&&x.road[1]&&y.ldrd)||(y.rurd))   ans.rurd=1;
        //更新的话自己照着图理解
        return ans;
    }
    void build(int p,int l,int r){
        if (l==r){
            tree[p].init();
            return;
        }
        int mid=(l+r)>>1;
        build(ls,l,mid),build(rs,mid+1,r);
    }
    void insert1(int p,int l,int r,int x,bool flag){
        if (l==r){
            tree[p].add(flag);
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid)  insert1(ls,l,mid,x,flag);
        if (x>mid)   insert1(rs,mid+1,r,x,flag);
        tree[p]=updata(tree[ls],tree[rs]);
    }
    void insert2(int p,int l,int r,int x,int y,bool flag){
        if (l==r){
            tree[p].road[y-1]=flag;
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid)  insert2(ls,l,mid,x,y,flag);
        if (x>mid)   insert2(rs,mid+1,r,x,y,flag);
        tree[p]=updata(tree[ls],tree[rs]);
    }
    AC query(int p,int l,int r,int x,int y){
        if (x<=l&&r<=y)   return tree[p];
        int mid=(l+r)>>1;
        AC ans1,ans2;
        bool left=0,right=0;
        if (x<=mid)  ans1=query(ls,l,mid,x,y),left=1;
        if (y>mid)   ans2=query(rs,mid+1,r,x,y),right=1;
        if (left&&right)    return updata(ans1,ans2);
        return left?ans1:ans2;
    }
    bool check(int r1,int c1,int r2,int c2){
        AC pre,now,last;
        if (c1>c2)   swap(c1,c2),swap(r1,r2);
        pre=query(1,1,n,1,c1);
        now=query(1,1,n,c1,c2);
        last=query(1,1,n,c2,n);
        //pre的右边和now的左边是重合的,now的右边和las的左边是重合的。不过pre记录的是1~c1的联通情况,和now不同,所以要分3个区间讨论
        if (r1==r2){//讨论自己按着图理解一下
            if ((r1==1)&&((now.luru)||(pre.rurd&&now.ldru)||(now.lurd&&last.luld)||(pre.rurd&&now.ldrd&&last.luld)))    return 1;
            if ((r1==2)&&((now.ldrd)||(pre.rurd&&now.lurd)||(now.ldru&&last.luld)||(pre.rurd&&now.luru&&last.luld)))    return 1;
        }else{
            if ((r1==1)&&((now.lurd)||(pre.rurd&&now.ldrd)||(now.luru&&last.luld)||(pre.rurd&&now.ldru&&last.luld)))    return 1;
            if ((r1==2)&&((now.ldru)||(pre.rurd&&now.luru)||(now.ldrd&&last.luld)||(pre.rurd&&now.lurd&&last.luld)))    return 1;
        }
        return 0;
    }
}Tree;
char s[10];
int main(){
    n=read();
    Tree.build(1,1,n);
    while (1){
        scanf("%s",s);
        if (s[0]==‘E‘)  break;
        int r1=read(),c1=read(),r2=read(),c2=read();
        if (s[0]==‘O‘){
            if (c1==c2) Tree.insert1(1,1,n,c1,1);
            else    Tree.insert2(1,1,n,min(c1,c2),r1,1);
        }
        if (s[0]==‘C‘){
            if (c1==c2) Tree.insert1(1,1,n,c1,0);
            else    Tree.insert2(1,1,n,min(c1,c2),r1,0);
        }
        if (s[0]==‘A‘){
            Tree.check(r1,c1,r2,c2)?putchar(‘Y‘):putchar(‘N‘);
            putchar(‘\n‘);
        }
    }
    return 0;
}
























以上是关于[SHOI2008]堵塞的交通traffic的主要内容,如果未能解决你的问题,请参考以下文章

[SHOI2008]堵塞的交通traffic

BZOJ1018[SHOI2008]堵塞的交通traffic 线段树

bzoj 1018: [SHOI2008]堵塞的交通traffic

[SHOI2008]堵塞的交通traffic

BZOJ 1018: [SHOI2008]堵塞的交通traffic [线段树 区间信息]

BZOJ1018: [SHOI2008]堵塞的交通traffic