bzoj 1018 [SHOI2008]堵塞的交通traffic

本文介绍了一种针对小人国特殊布局的交通查询系统实现方法。系统通过维护线段树来更新道路的连通状态,并能高效地回答城市间是否连通的查询。文章详细解释了线段树的维护过程及查询算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.elijahqi.win/archives/3425
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

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

Source

感觉足够难写的一题

借用bzoj题解的图

这里写图片描述

针对每个两行的矩形区域维护线段树 每个区间维护线段树管辖的这个区间的边界的联通情况 即该线段树区域本应该是1,4 那么维护的值就是1和4的连通情况

考虑这个矩形是

s1,s2

s3,s4这样的一个矩形

线段树上维护6个值

U 第一行线段树上区间mid,mid+1的连通情况

D 第二行线段树上区间mid,mid+1的连通情况

u 第一行线段树上区间左端点到右端点的连通情况

d 第二行线段树上区间左端点到右端点的连通情况

l 左端点第一行和第二行的连通情况

r 右端点 第一行和第二行的连通情况

p 刚刚所画矩形s3,s2的联通情况

q 矩形s1,s4的连通情况

剩下在维护的时候我们只考虑是否连通 不用考虑是否走什么样的路线

注意如果l==r的时候即只有上下两个格子的时候要提前把u,d,U,D变成1即可

询问的时候分是否在同一行 分类讨论 因为有可能从外部绕过去 所以询问的时候也需要把 前缀还有后缀的提前处理出来 最后 关于合并的细节 耐心推导看代码

#include<cstdio>
#include<cctype>
#include<algorithm>
#define lc (x<<1)
#define rc (x<<1|1)
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int N=1e5+10;
struct node{
    int U,D,l,r,u,d,p,q;
}w[N<<2];
char s[10];int n;
inline void build(int x,int l,int r){
    if (l==r) {w[x].U=w[x].D=w[x].u=w[x].d=1;return;}
    int mid=l+r>>1;build(lc,l,mid);build(rc,mid+1,r);
}
inline void merge(node &x,const node &l,const node &r){
    x.l=l.l|(l.u&x.U&r.l&x.D&l.d);
    x.r=r.r|(r.u&x.U&l.r&x.D&r.d);
    x.u=(l.u&x.U&r.u)|(l.q&x.D&r.p);
    x.d=(l.d&x.D&r.d)|(l.p&x.U&r.q);
    x.q=(l.u&x.U&r.q)|(l.q&x.D&r.d);
    x.p=(l.d&x.D&r.p)|(l.p&x.U&r.u);
//  printf("%d %d %d %d %d %d\n",x.l,x.r,x.u,x.d,x.q,x.p);
}
inline void modifyr(int x,int l,int r,int p,int now,int v){
    int mid=l+r>>1;
    if (mid==p){
        if (now==1) w[x].U=v;else w[x].D=v;merge(w[x],w[lc],w[rc]);return;
    }
    if (p<=mid) modifyr(lc,l,mid,p,now,v);else modifyr(rc,mid+1,r,p,now,v);
    merge(w[x],w[lc],w[rc]);
}
inline void modifyc(int x,int l,int r,int p,int v){
    if (l==r){w[x].l=w[x].r=w[x].p=w[x].q=v;return;}int mid=l+r>>1;
    if (p<=mid) modifyc(lc,l,mid,p,v);else modifyc(rc,mid+1,r,p,v);
    merge(w[x],w[lc],w[rc]);
}
inline node query(int x,int l,int r,int l1,int r1){
    if(l1<=l&&r1>=r) return w[x];int mid=l+r>>1;
    if (r1<=mid) return query(lc,l,mid,l1,r1);
    if (l1>mid) return query(rc,mid+1,r,l1,r1);
    node tmp=w[x],tmp1=query(lc,l,mid,l1,r1),tmp2=query(rc,mid+1,r,l1,r1);
    merge(tmp,tmp1,tmp2);return tmp;
}
int main(){
    //freopen("7.in","r",stdin);
//  freopen("1.out","w",stdout);
    n=read();build(1,1,n);int cnt=0;
    while(1){
        scanf("%s",s+1);if (s[1]=='E') return 0;
        int r1=read(),c1=read(),r2=read(),c2=read();
        if (c1>c2) swap(c1,c2),swap(r1,r2);
        if (s[1]=='O'){
            if (r1==r2) modifyr(1,1,n,c1,r1,1);
            else modifyc(1,1,n,c1,1);
        }
        if (s[1]=='C'){
            if (r1==r2) modifyr(1,1,n,c1,r1,0);
            else modifyc(1,1,n,c1,0);
        }
        if (s[1]=='A'){
            static node l,x,r;bool ans;//++cnt;if (cnt==12) break;
            l=query(1,1,n,1,c1);x=query(1,1,n,c1,c2);r=query(1,1,n,c2,n);
            if (r1==1&&r2==1){
                ans=x.u|(l.r&x.p)|(x.q&r.l)|(l.r&x.d&r.l);
            }
            if (r1==1&&r2==2){
                ans=x.q|(l.r&x.d)|(x.u&r.l)|(l.r&x.p&r.l);
            }
            if (r1==2&&r2==1){
                ans=x.p|(l.r&x.u)|(x.d&r.l)|(l.r&x.q&r.l);
            }
            if (r1==2&&r2==2){
                ans=x.d|(l.r&x.q)|(x.p&r.l)|(l.r&x.u&&r.l);
            }ans?puts("Y"):puts("N");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值