[BZOJ 1018][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

Solution

线段树维护连通性

a数组表示矩形左上与右上,左上与右下,左下与右上,左下与右下分别是否联通

b数组表示矩形左端和右端各自是否上下相连

这种情况完全可以直接查询两点间的矩形对不对

然而如果路线绕了一个圈…O O

这时候就可以用上b数组了,查询该矩形(指两点间的矩形)以左的所有部分是否能使得左端的上下两个点联通、以右的所有部分是否能使得右端的上下两个点联通

然后分类讨论啊啥的

(一开始只维护了a,想用一些奇怪的方法,写着写着发现不太对,改改改改改…)

代码写的不是很优雅,某些细节十分鸡肋…可能是因为改了太多次

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define MAXN 100005
#define Min(a,b) (a<b?a:b)
using namespace std;
int c;
bool col[MAXN],row1[MAXN],row2[MAXN];
struct Node{
    int l,r;
    bool a[2][2];
    bool b[2];
    Node(){l=r=0;memset(a,0,sizeof(a));memset(b,0,sizeof(0));}
}t[4*MAXN];
Node operator + (const Node& A,const Node& B)
{
    Node C;
    C.l=A.l,C.r=B.r;
    C.a[0][0]=(A.a[0][0]&&B.a[0][0])||(A.a[0][1]&&B.a[1][0]);
    C.a[0][1]=(A.a[0][0]&&B.a[0][1])||(A.a[0][1]&&B.a[1][1]);
    C.a[1][0]=(A.a[1][0]&&B.a[0][0])||(A.a[1][1]&&B.a[1][0]);
    C.a[1][1]=(A.a[1][1]&&B.a[1][1])||(A.a[1][0]&&B.a[0][1]);
    if(A.b[0]||(C.a[0][0]&&C.a[1][0])||(C.a[0][1]&&C.a[1][1]))C.b[0]=1;
    else C.b[0]=0;
    if(B.b[1]||(C.a[0][0]&&C.a[0][1])||(C.a[1][0]&&C.a[1][1]))C.b[1]=1;
    else C.b[1]=0;
    return C;
}
int Read()
{
    int x=0,f=1;char c=getchar();
    while(c<‘0‘||c>‘9‘){
        if(c==‘-‘)f=-1;c=getchar();
    }
    while(c>=‘0‘&&c<=‘9‘){
        x=x*10+c-‘0‘;c=getchar();
    }
    return x*f;
}
void Build(int idx,int l,int r)
{
    t[idx].l=l,t[idx].r=r;
    if(l==r)
    return;
    int mid=(l+r)>>1;
    Build(idx<<1,l,mid);
    Build(idx<<1|1,mid+1,r);
}
void Change(int idx,int x)
{
    if(t[idx].l==t[idx].r)
    {
        t[idx].a[0][0]=t[idx].a[1][1]=t[idx].a[0][1]=t[idx].a[1][0]=0;
        if(row1[x])t[idx].a[0][0]=1;
        if(row2[x])t[idx].a[1][1]=1;
        if(col[x])
        t[idx].a[0][1]|=t[idx].a[1][1],t[idx].a[1][0]|=t[idx].a[0][0];
        if(col[x+1])
        t[idx].a[0][1]|=t[idx].a[0][0],t[idx].a[1][0]|=t[idx].a[1][1];
        if(col[x]&&col[x+1])
        t[idx].a[0][0]|=t[idx].a[1][1],t[idx].a[1][1]|=t[idx].a[0][0];

        t[idx].b[0]=col[t[idx].l],t[idx].b[1]=col[t[idx].l+1];
        if((t[idx].a[0][0]&&t[idx].a[1][0])||(t[idx].a[0][1]&&t[idx].a[1][1]))t[idx].b[0]=1;
        if((t[idx].a[0][0]&&t[idx].a[0][1])||(t[idx].a[1][0]&&t[idx].a[1][1]))t[idx].b[1]=1;
        return;
    }
    int mid=(t[idx].l+t[idx].r)>>1;
    if(x<=mid)Change(idx<<1,x);
    else Change(idx<<1|1,x);
    t[idx]=t[idx<<1]+t[idx<<1|1];
}
Node Ask(int idx,int x,int y)
{
    if(x>y)return Node();
    if(t[idx].l>=x&&t[idx].r<=y)
    return t[idx];
    int mid=(t[idx].l+t[idx].r)>>1;
    if(y<=mid)
    return Ask(idx<<1,x,y);
    else if(x>mid)
    return Ask(idx<<1|1,x,y);
    else
    return Ask(idx<<1,x,y)+Ask(idx<<1|1,x,y);
}
int main()
{
    c=Read();
    for(int i=1;i<=c;i++)col[i]=0;
    for(int i=1;i<c;i++)row1[i]=row2[i]=0;
    Build(1,1,c-1);
    while(1)
    {
        char opt[10];int r1,c1,r2,c2;
        scanf("%s",opt);
        if(!strcmp(opt,"Exit"))
        break;
        r1=Read();c1=Read();r2=Read();c2=Read();
        if(!strcmp(opt,"Open"))
        {
            if(r1==r2)
            {
                if(c1>c2)swap(c1,c2);
                if(r1==1)row1[c1]=1;
                else row2[c1]=1;
                Change(1,c1);
            }
            else if(c1==c2)
            {
                col[c1]=1;
                if(c1-1>0)Change(1,c1-1);
                if(c1<c)Change(1,c1);
            }
        }
        else if(!strcmp(opt,"Close"))
        {
            if(r1==r2)
            {
                if(c1>c2)swap(c1,c2);
                if(r1==1)row1[c1]=0;
                else row2[c1]=0;
                Change(1,c1);
            }
            else if(c1==c2)
            {
                col[c1]=0;
                if(c1-1>0)Change(1,c1-1);
                if(c1<c)Change(1,c1);
            }
        }
        else if(!strcmp(opt,"Ask"))
        {
            if(c1>c2)swap(c1,c2),swap(r1,r2);
            r1--;r2--;
            Node x=Ask(1,1,c1-1),y=Ask(1,c2,c-1),z=Ask(1,c1,c2-1);
            bool flag=0;
            if(c1==c2&&(r1==r2||x.b[1]||y.b[0]))flag=1;
            for(int i=0;i<=1;i++)
            for(int j=0;j<=1;j++)
            {
                if((i==r1||x.b[1])&&(j==r2||y.b[0])&&(z.a[i][j]))
                flag=1;
            }
            if(flag)
            printf("Y\n");
            else printf("N\n");
        }
    }
    return 0;
} 
时间: 2024-10-13 08:05:14

[BZOJ 1018][SHOI2008]堵塞的交通traffic(线段树)的相关文章

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

1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 3064  Solved: 1027[Submit][Status][Discuss] Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路. 小人国的交通

BZOJ 1018 SHOI2008 堵塞的交通traffic 线段树

题目大意:给定一张2*n的网格图,多次改变某条边是否可用,多次查询某两个点是否联通 多(yi)年前的我看到这题的第一反应是:这题尼玛能做? 两个点之间的路径可能是这样的: 也可能是这样的: 甚至可能是这样的: 这题能写? 这题其实好写爆了 我们首先忽略第三种情况,假设所有对答案有贡献的边都在两个点的中间 那么我们以每一列为一个叶节点建立线段树 线段树的每个节点开一个二维数组a[2][2] 其中 a[x][y]记录当前区间的左端点的第x行和右端点的第y行是否联通 那么合并如下: 例如,a[0][0

数据结构(线段树):BZOJ 1018: [SHOI2008]堵塞的交通traffic

1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 2638  Solved: 864 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路. 小人国的交通状况非常槽糕.有的时候由于交通堵塞,两座城市之间的道

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

[BZOJ1018][SHOI2008]堵塞的交通traffic Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路. 小人国的交通状况非常槽糕.有的时候由于交通堵塞,两座城市之间的道路会变得不连通,直到拥堵解决,道路才会恢复畅通.初来咋到的你决心毛遂自荐到交通部某份差事,部长听说你来自一个科技高度发达的

[BZOJ 1018] [SHOI2008] 堵塞的交通traffic 【线段树维护联通性】

题目链接:BZOJ - 1018 题目分析 这道题就说明了刷题少,比赛就容易跪..SDOI Round1 Day2 T3 就是与这道题类似的..然而我并没有做过这道题.. 这道题是线段树维护联通性的经典模型. 我们线段树的一个节点表示一个区间的联通性,有 6 个 bool 值,表示这个区间的 4 个角上的点之间的联通性. 然后用两个子区间的联通性和两个子区间之间的连边情况合并出整个区间的联通性. 修改某条边时,先在边的数组中修改,然后从这条边所在的点的线段树叶子开始向上 Update . 询问两

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

由于只有两行,对一个区间可以维护四个角上的连通性 一共6个量,满足区间可加性,用线段树维护,查询时找出3段的量,看是否满足题解上的三种情况之一. 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8

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

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1018 线段树竟然还可以这样用! 维护的是一个矩形内部的连通情况,四个顶点之间有6中连通方式: 因为连通情况具有可合并性,所以可以用线段树来维护! 这篇博客写得很好:https://www.cnblogs.com/DUXT/p/6029815.html 茅塞顿开之后看到这篇博客,觉得写得很好呢:https://www.cnblogs.com/MashiroSky/p/5973686.html

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

线段树维护每一块左上到左下.右上到右下.左上到右上.左下到右下.左上到右下.左下到右上的联通情况. #include<bits/stdc++.h> #define N 100005 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define K l,r,k #define L l,M,P #define R M+1,r,S #define Z int l=1,int r=n,int k=1 u

1018: [SHOI2008]堵塞的交通traffic

1018: [SHOI2008]堵塞的交通traffic 链接 分析: 用线段树维护区间的四个端点的联通情况,然后查询的时候,把所有覆盖到的区间合并起来即可. 六种情况左上到右上(左边到右边的情况)……,左上到左下(同一侧相互到达的情况)…… 同一侧相互到达的情况,查询[l,r]是查的不完全.因为还有可能是先往左边走几步,下去,在走回来.这时候,查询一下[1,l]的情况,或起来即可. 代码: 1 #include<cstdio> 2 #include<algorithm> 3 #i