BZOJ1018线段树

Posted Billyshuai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1018线段树相关的知识,希望对你有一定的参考价值。

1018: [SHOI2008]堵塞的交通traffic

Time Limit: 3 Sec  Memory Limit: 162 MB
Submit: 3489  Solved: 1168
[Submit][Status][Discuss]

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

HINT

 
http://www.cnblogs.com/Sdchr/p/6104781.html//先贴参考代码
 
大体如下:
将每列作为线段树的叶节点,然后的话节点保存的是其左边界的第一行与右边界的第一行是否联通(a1[0][0])左边界的第一行与右边界的第二行是否联通(a1[0][1])然后一共有a1[2][2]
还有还有左右边界上下是否连通(a2[2]),还有一个神奇的中间联通点b[n<<2][2]表示两个区间的中间部分是否连通b[x][0]是第一行,b[x][1]是第二行。
这种带有区间更新意味的线段树,还有HDU的3308
 
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=800000+88;
char s[20];
int x1,x2,y1,y2,c;
struct Segtree{
    struct Status{
    int a1[2][2],a2[2];
    }s[maxn];
    bool b[maxn][2];
    int l[maxn],r[maxn],m[maxn];
    Status update(Status s1,Status s2,bool b[]) {
    Status res;
    for(int i=0;i<=1;++i)
        for(int j=0;j<=1;++j)
        res.a1[i][j]=(s1.a1[i][0]&&b[0]&&s2.a1[0][j])||(s1.a1[i][1]&&b[1]&&s2.a1[1][j]);
        res.a2[0]=(s1.a2[0])||(s1.a1[0][0]&&b[0]&&s2.a2[0]&&b[1]&&s1.a1[1][1]);
        res.a2[1]=(s2.a2[1])||(s2.a1[0][0]&&b[0]&&s1.a2[1]&&b[1]&&s2.a1[1][1]);
        return res;
    }
    Status access(int x,int y1,int y2){
    if(y1<=l[x]&&r[x]<=y2) return s[x];
    else if(y2<=m[x]) return access(x<<1,y1,y2);
    else if(y1>m[x]) return access(x<<1|1,y1,y2);
    else return update(access(x<<1,y1,y2),access(x<<1|1,y1,y2),b[x]);
    }
    void change(bool k,int x,int x1,int y1,int x2,int y2){
    if(x1==x2&&y1==m[x]) {
        b[x][x1]=k;
        s[x]=update(s[x<<1],s[x<<1|1],b[x]);
    }
    else if(l[x]==r[x]) s[x].a1[0][1]=s[x].a1[1][0]=s[x].a2[0]=s[x].a2[1]=k;
    else {
        change(k,y2<=m[x]?x<<1:x<<1|1,x1,y1,x2,y2);
        s[x]=update(s[x<<1],s[x<<1|1],b[x]);
    }
    }
    void ask(int x1,int y1,int x2,int y2){
    Status left=access(1,1,y1),right=access(1,y2,c),mid=access(1,y1,y2);
    bool res=false;
    for(int i=0;i<=1;++i)
        for(int j=0;j<=1;++j)
    if(mid.a1[i][j]&&(i==x1||left.a2[1])&&(j==x2||right.a2[0])) {
        res=true;
        break;
    }
    if(res) puts("Y"); else puts("N");
    }
    void build(int x,int y1,int y2){
    l[x]=y1,r[x]=y2,m[x]=(l[x]+r[x])>>1;
    if(y1==y2) s[x].a1[0][0]=s[x].a1[1][1]=true;
    else {
        build(x<<1,y1,m[x]);
        build(x<<1|1,m[x]+1,y2);
    }
    }
}seg;
int main(){
   scanf("%d",&c);
   seg.build(1,1,c);
   while(1){
    scanf("%s",s);
    if(s[0]==\'E\') break;
    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    --x1;--x2;
    if(y1>y2) {
        swap(x1,x2);
        swap(y1,y2);
    }
    if(s[0]==\'O\') seg.change(1,1,x1,y1,x2,y2);
    else if(s[0]==\'C\') seg.change(0,1,x1,y1,x2,y2);
    else seg.ask(x1,y1,x2,y2);
   }
   return 0;
}
 

 

以上是关于BZOJ1018线段树的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 1018--堵塞的交通(线段树)

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

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

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

BZOJ 1018 线段树维护图的连通性问题

bzoj 1018 堵塞的交通traffic 线段树