[SHOI2008]堵塞的交通

Posted alecli

tags:

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

题意

Here

思考

一道很好的线段树题 (&&) 一道很毒瘤的码农题

一开始完全没想到用线段树来维护这种网格的连通性,后来看题解之后发现实在是妙啊……(满足区间可合并性)

线段树维护的是一段区间的四个端点间两两的连通信息,六个变量,合并时由于要考虑两块是否可合并,还得维护区间中间两点是否连通,两个变量。所以总共是八个变量,合并的时候分类讨论有些复杂,具体见代码。

代码

#include<bits/stdc++.h>
#define ls(pos) pos << 1
#define rs(pos) pos << 1 | 1
using namespace std;
const int N = 200020;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x * f;
}
struct node{
    int l, r, u, d, p, q, mid1, mid2;
};
namespace Seg{
    int l[N << 2], r[N << 2], u[N << 2], d[N << 2], p[N << 2], q[N << 2], mid1[N << 2], mid2[N << 2];
    ///l左侧上下 r右侧上下 u上 d下 p左上右下 q左下右上 mid1第一行中间是否联通 mid2第二行…
    void pushup(int pos){
        l[pos] = l[ls(pos)] || (u[ls(pos)] && mid1[pos] && l[rs(pos)] && mid2[pos] && d[ls(pos)]);
        r[pos] = r[rs(pos)] || (u[rs(pos)] && mid1[pos] && r[ls(pos)] && mid2[pos] && d[rs(pos)]);
        u[pos] = (u[ls(pos)] && u[rs(pos)] && mid1[pos]) || (p[ls(pos)] && mid2[pos] && q[rs(pos)]);
        d[pos] = (d[ls(pos)] && d[rs(pos)] && mid2[pos]) || (q[ls(pos)] && mid1[pos] && p[rs(pos)]);
        p[pos] = (p[ls(pos)] && mid2[pos] && d[rs(pos)]) || (u[ls(pos)] && mid1[pos] && p[rs(pos)]);
        q[pos] = (q[ls(pos)] && mid1[pos] && u[rs(pos)]) || (d[ls(pos)] && mid2[pos] && q[rs(pos)]);
    }
    void build(int pos, int ll, int rr){
        if(ll == rr){
            mid1[pos] = mid2[pos] = u[pos] = d[pos] = 1;
            return ;
        }
        int mid = (ll + rr) >> 1;
        build(ls(pos), ll, mid);
        build(rs(pos), mid+1, rr);
    }
    void modify(int pos, int ll, int rr, int x, int v){///竖
        if(ll == rr){
            l[pos] = r[pos] = p[pos] = q[pos] = v;
            return ;
        }
        int mid = (ll + rr) >> 1;
        if(x <= mid) modify(ls(pos), ll, mid, x, v);
        else modify(rs(pos), mid+1, rr, x, v);
        pushup(pos);
    }
    void modify2(int pos, int ll, int rr, int op, int x, int v){///横
        int mid = (ll + rr) >> 1;
        if(mid == x){
            if(op == 1) mid1[pos] = v;
            else mid2[pos] = v;
            pushup(pos);
            return ;
        }
        if(x <= mid) modify2(ls(pos), ll, mid, op, x, v);
        else modify2(rs(pos), mid+1, rr, op, x, v);
        pushup(pos);
    }
    node query(int pos, int ll, int rr, int x, int y){
        if(x <= ll && rr <= y){
            node ans = (node){l[pos], r[pos], u[pos], d[pos], p[pos], q[pos], mid1[pos], mid2[pos]};
            return ans;
        }
        int mid = (ll + rr) >> 1;
        if(y <= mid) return query(ls(pos), ll, mid, x, y);
        else if(x > mid) return query(rs(pos), mid+1, rr, x, y);
        else{
            node ans = (node){l[pos], r[pos], u[pos], d[pos], p[pos], q[pos], mid1[pos], mid2[pos]};
            node ansl = query(ls(pos), ll, mid, x, y), ansr = query(rs(pos), mid+1, rr, x, y);
            ans.l = ansl.l || (ansl.u && ans.mid1 && ansr.l && ans.mid2 && ansl.d);
            ans.r = ansr.r || (ansr.u && ans.mid1 && ansl.r && ans.mid2 && ansr.d);
            ans.u = (ansl.u && ansr.u && ans.mid1) || (ansl.p && ans.mid2 && ansr.q);
            ans.d = (ansl.d && ansr.d && ans.mid2) || (ansl.q && ans.mid1 && ansr.p);
            ans.p = (ansl.p && ans.mid2 && ansr.d) || (ansl.u && ans.mid1 && ansr.p);
            ans.q = (ansl.q && ans.mid1 && ansr.u) || (ansl.d && ans.mid2 && ansr.q);
            return ans;
        }
    }
}
using namespace Seg;
int n;
int main(){
    n = read();
    build(1, 1, n);
    while(233){
        char op[20]; cin >> op + 1;
        if(op[1] == ‘E‘) break;
        int r1 = read(), c1 = read(), r2 = read(), c2 = read();
        if(c1 > c2) swap(c1, c2), swap(r1, r2);
        if(op[1] == ‘O‘){
            if(c1 == c2) modify(1, 1, n, c1, 1);
            else modify2(1, 1, n, r1, c1, 1);
        }
        if(op[1] == ‘C‘){
            if(c1 == c2) modify(1, 1, n, c1, 0);
            else modify2(1, 1, n, r1, c1, 0);
        }
        if(op[1] == ‘A‘){
            int ans = 0;
            node l = query(1, 1, n, 1, c1), mid = query(1, 1, n, c1, c2), r = query(1, 1, n, c2, n);
            if(r1 == 1 && r2 == 1) ans = mid.u || (l.r && mid.q) || (r.l && mid.p) || (l.r && mid.d && r.l);
            if(r1 == 2 && r2 == 2) ans = mid.d || (l.r && mid.p) || (r.l && mid.q) || (l.r && mid.u && r.l);
            if(r1 == 1 && r2 == 2) ans = mid.p || (l.r && mid.d) || (r.l && mid.u) || (l.r && mid.q && r.l);
            if(r1 == 2 && r2 == 1) ans = mid.q || (l.r && mid.u) || (r.l && mid.d) || (l.r && mid.p && r.l);
            if(ans) puts("Y");
            else puts("N");
        }
    }
    return 0;
}

总结

这题细节很多,也比较锻炼码力吧,我觉得以后遇到这种题还是要有足够的把握才写正解,写正解的话也要注意:把变量的用途尽量注释出来,写程序时多多检查,多调试,保证每步要正确,不然查错的时候??

以上是关于[SHOI2008]堵塞的交通的主要内容,如果未能解决你的问题,请参考以下文章

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

1018: [SHOI2008]堵塞的交通traffic

[SHOI2008]堵塞的交通traffic

[SHOI2008]堵塞的交通

[SHOI2008]堵塞的交通traffic

[SHOI2008]堵塞的交通