bzoj1018: [SHOI2008]堵塞的交通traffic

题目
题解

Solution

一道用线段树维护连通性的题。
第一做这种题,其实这类问题我们需要维护一下区间内的联通关系,再用我们维护的这些关系去查询。
对于这道题,我觉得可以有两种建树的方法:
①:以每一列为一个叶子节点。
②:以每一个区间(就是每1条横向道路连接的左右两个节点)为一个叶子节点。
我选择的是第一种,我们首先需要维护6个变量(也就是区间内的6种联通关系),分别是luru,ldrd,lurd,ldru,luld,rurd(l:left;r:right;u:up;d:down)
然后由于还有修改横向相邻的道路,所以我们还要维护一个side[]表示这个节点是否可以向外延伸。
最后就是最麻烦的查询了,需要分很多种情况讨论,尤其是当我们查询的这段区间的联通性需要借助它以外的区间才可以联通的这种情况,这些情况就不一一赘述了,具体的看代码吧。

Code

#include<bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
const int N=100002;
int n,i,r1,c1,r2,c2;
char s[9];
struct S{
    bool luld,rurd,luru,ldrd,lurd,ldru,s[2];
}tr[N<<2];
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline int read(){
    int x=0,fl=1;char ch=gc();
    for (;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
    for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
    return x*fl;
}
S up(S x,S y){
    S ans;
    ans.s[0]=y.s[0];ans.s[1]=y.s[1];
    ans.luru=(x.luru && x.s[0] && y.luru || x.lurd && x.s[1] && y.ldru);
    ans.ldrd=(x.ldrd && x.s[1] && y.ldrd || x.ldru && x.s[0] && y.lurd);
    ans.lurd=(x.luru && x.s[0] && y.lurd || x.lurd && x.s[1] && y.ldrd);
    ans.ldru=(x.ldrd && x.s[1] && y.ldru || x.ldru && x.s[0] && y.luru);
    ans.luld=(x.luld || x.luru && x.s[0] && y.luld && x.s[1] && x.ldrd);
    ans.rurd=(y.rurd || y.luru && x.s[0] && x.rurd && x.s[1] && y.ldrd);
    return ans;
}
void build(int t,int l,int r){
    if (l==r){
        tr[t].luru=tr[t].ldrd=1;
        return;
    }
    build(t<<1,l,mid);
    build(t<<1|1,mid+1,r);
    tr[t]=up(tr[t<<1],tr[t<<1|1]);
}
void ins_a(int t,int l,int r,int x,bool op){//上下 
    if (l==r){
        tr[t].luld=tr[t].rurd=tr[t].lurd=tr[t].ldru=op;
        return;
    }
    if (x<=mid) ins_a(t<<1,l,mid,x,op);
    else ins_a(t<<1|1,mid+1,r,x,op);
    tr[t]=up(tr[t<<1],tr[t<<1|1]);
}
void ins_b(int t,int l,int r,int x,int y,bool op){//左右
    if (l==r){
        tr[t].s[y]=op;
        return;
    }
    if (x<=mid) ins_b(t<<1,l,mid,x,y,op);
    else ins_b(t<<1|1,mid+1,r,x,y,op);
    tr[t]=up(tr[t<<1],tr[t<<1|1]);
}
S query(int t,int l,int r,int x,int y){
    if (x<=l && r<=y) return tr[t];
    bool le=0,ri=0;
    S ans1,ans2;
    if (x<=mid) ans1=query(t<<1,l,mid,x,y),le=1;
    if (mid<y) ans2=query(t<<1|1,mid+1,r,x,y),ri=1;
    if (le && ri) return up(ans1,ans2);
    return le?ans1:ans2;
}
bool check(){
    if (c1>c2) swap(c1,c2),swap(r1,r2);
    S now=query(1,1,n,c1,c2),pre=query(1,1,n,1,c1),las=query(1,1,n,c2,n);
    if (r1==r2){
        if (!r1) return now.luru || pre.rurd && now.ldru || las.luld && now.lurd || pre.rurd && now.ldrd && las.luld;
            else return now.ldrd || pre.rurd && now.lurd || las.luld && now.ldru || pre.rurd && now.luru && las.luld;
    }else{
        if (!r1) return now.lurd || pre.rurd && now.ldrd || las.luld && now.luru || pre.rurd && now.ldru && las.luld;
            else return now.ldru || pre.rurd && now.luru || las.luld && now.ldrd || pre.rurd && now.lurd && las.luld;
    }
}
int main(){
    n=read();
    build(1,1,n);
    while (1){
        scanf("%s",s);
        if (s[0]=='E') break;
        r1=read()-1;c1=read();r2=read()-1;c2=read();
        if (s[0]=='A') puts(check()?"Y":"N");
        else{
            if (c1==c2) ins_a(1,1,n,c1,s[0]=='O');
            else ins_b(1,1,n,min(c1,c2),r1,s[0]=='O');
        }
    }
}

猜你喜欢

转载自blog.csdn.net/xumingyang0/article/details/81166325