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

我就是模仿上面第二篇博客写的,感觉自己对线段树的认识又加深了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=100005;
int c,r1,r2,c1,c2;
char ch[10];
struct N{int U,D,u,d,l,r,p,q;}w[maxn<<2];
struct T{int l,r;}tr[maxn<<2];
void merge(N &k,N x,N y)//&
{
    k.l=x.l|(x.u & k.U & y.l & k.D  &x.d);
    k.r=y.r|(y.u & k.U & x.r & k.D & y.d);
    k.u=(x.u & k.U & y.u)|(x.q & k.D & y.p);
    k.d=(x.d & k.D & y.d)|(x.p & k.U & y.q);
    k.p=(x.d & k.D & y.p)|(x.p & k.U & y.u);
    k.q=(x.u & k.U & y.q)|(x.q & k.D & y.d);
}
void build(int k,int l,int r)
{
    tr[k].l=l; tr[k].r=r;
    if(l==r){w[k].U=w[k].D=w[k].u=w[k].d=1;return;}
    int mid=((l+r)>>1);
    build(k<<1,l,mid); build(k<<1|1,mid+1,r);
//    merge(w[k],w[k<<1],w[k<<1|1]);//初始全不连通
}
void updater(int k,int T,int x,int val)//同一行
{
    int l=tr[k].l,r=tr[k].r,mid=((l+r)>>1);
    if(x==mid)
    {
        if(T==1) w[k].U=val;
        else w[k].D=val;
        merge(w[k],w[k<<1],w[k<<1|1]);
        return;
    }
    if(x<=mid) updater(k<<1,T,x,val);
    else updater(k<<1|1,T,x,val);
    merge(w[k],w[k<<1],w[k<<1|1]);
}
void updatec(int k,int x,int val)//同一列
{
    int l=tr[k].l,r=tr[k].r,mid=((l+r)>>1);
    if(l==r){w[k].l=w[k].r=w[k].p=w[k].q=val;return;}
    if(x<=mid) updatec(k<<1,x,val);
    else updatec(k<<1|1,x,val);
    merge(w[k],w[k<<1],w[k<<1|1]);
}
N query(int k,int l,int r)
{
    int s=tr[k].l,t=tr[k].r,mid=((s+t)>>1);
    if(s>=l&&t<=r) return w[k];
    if(r<=mid) return query(k<<1,l,r);
    else if(l>mid) return query(k<<1|1,l,r);
    else
    {
        N ret=w[k];//保留 U,D
        merge(ret,query(k<<1,l,r),query(k<<1|1,l,r));
        return ret;
    }
}
int main()
{
    scanf("%d",&c);
    build(1,1,c);
    while(1)
    {
        scanf("%s",&ch);
        if(ch[0]==‘E‘)return 0;
        scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
        if(c1>c2) swap(c1,c2),swap(r1,r2);
        if(ch[0]==‘O‘)
        {
            if(r1==r2)updater(1,r1,c1,1);
            else updatec(1,c1,1);
        }
        if(ch[0]==‘C‘)
        {
            if(r1==r2)updater(1,r1,c1,0);
            else updatec(1,c1,0);
        }
        if(ch[0]==‘A‘)
        {
            N l=query(1,1,c1),x=query(1,c1,c2),r=query(1,c2,c);
            int ans=0;
            if(r1==1&&r2==1)
                ans=x.u|(l.r & x.d & r.l)|(x.q & r.l)|(l.r & x.p);
            if(r1==1&&r2==2)
                ans=x.q|(l.r & x.p & r.l)|(l.r & x.d)|(x.u & r.l);
            if(r1==2&&r2==1)
                ans=x.p|(l.r & x.q & r.l)|(l.r & x.u)|(x.d & r.l);
            if(r1==2&&r2==2)
                ans=x.d|(l.r & x.u & r.l)|(x.p & r.l)|(l.r & x.q);
            if(ans) printf("Y\n");
            else printf("N\n");
        }
    }
}

原文地址:https://www.cnblogs.com/Zinn/p/9169122.html

时间: 2024-10-21 07:58:54

bzoj1018 [SHOI2008]堵塞的交通traffic——线段树的相关文章

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

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

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

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

【BZOJ1018】堵塞的交通(线段树)

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

bzoj千题计划108:bzoj1018: [SHOI2008]堵塞的交通traffic

http://www.lydsy.com/JudgeOnline/problem.php?id=1018 关键点在于只有两行 所以一个2*m矩形连通情况只有6种 编号即对应代码中的a数组 线段树维护 用b数组表示 节点第0/1行的最右一列是否连接了右边 来 辅助 节点的合并 查询 对两个点位于矩形的位置分4种情况讨论 两点是否联通,要考虑四种情况 (以两个位置是矩形左上角和右上角为例) 1.直接联通,线段树的节点包含了这种情况,直接判断 2. 3. 4. 后三种情况需要再查询[1,l]和[r,n

Bzoj1018 [SHOI2008]堵塞的交通traffic

Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 3458  Solved: 1158 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路. 小人国的交通状况非常槽糕.有的时候由于交通堵塞,两座城市之间的道路会变得不连通,直到拥堵解决,道路才会恢复畅通.初来咋到

bzoj 1018 堵塞的交通traffic 线段树

题意:有一个n * 2的网格图,有3种操作:给两个相邻的点加上一条边,断开相邻的两个点连着的边,询问两个点的连通性. 思路:直接看博客就行了,https://blog.csdn.net/roll_keyboard/article/details/81185535,在纸上画一画来确定4个顶点之间的更新关系.有一个需要注意的细节是有可能通过绕远路的方式可以到达,所以需要考虑前面和后面的部分对询问区间的影响. 代码: #include <bits/stdc++.h> #define ls (o &l

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

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