zoukankan      html  css  js  c++  java
  • BZOJ 1018 线段树维护图的连通性问题

    思路:

    我们可以搞一棵线段树

    对于一段区间有6种情况需要讨论

    左上右下、左上右上、左下右下、左下右上

    这四种比较好维护

    用左上右下举个例子吧

    就是左儿子的左上右下&左区间到右区间下面有路&右儿子的左下右下

    或者是左儿子的左上右上&左区间到右区间上面有路&右儿子的左上右下

    还有两种  区间的左(右)端点上下能不能联通 需要维护

    这种就是左儿子的上下连通或(左上右上&左上右下&左到右两条路都联通&右儿子的上下联通)

    (假设c1<c2)

    最后要查的是 1->c1 (可以1~c1上下联通再c1[!r1]->c2)

    c1->c2(直接联通当然最好)

    c2->cn

    还有一种是1~c1上下联通&c2~n上下联通&c1[!r1]与c2[!r2]上下联通

    4种分类讨论即可

    //By SiriusRen
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N=100050;
    int map[N][2],map2[N],n,r1,c1,r2,c2,jy;
    char op[15];
    struct Node{bool b[2][2],c[2];}tree[N*16];
    Node push_up(Node L,Node R,int mid){
        Node tmp;
        tmp.b[0][0]=(L.b[0][0]&map[mid][0]&R.b[0][0])|(L.b[0][1]&map[mid][1]&R.b[1][0]);
        tmp.b[0][1]=(L.b[0][0]&map[mid][0]&R.b[0][1])|(L.b[0][1]&map[mid][1]&R.b[1][1]);
        tmp.b[1][0]=(L.b[1][0]&map[mid][0]&R.b[0][0])|(L.b[1][1]&map[mid][1]&R.b[1][0]);
        tmp.b[1][1]=(L.b[1][0]&map[mid][0]&R.b[0][1])|(L.b[1][1]&map[mid][1]&R.b[1][1]);
        tmp.c[0]=L.c[0]|(L.b[0][0]&map[mid][0]&map[mid][1]&L.b[1][1]&R.c[0]);
        tmp.c[1]=R.c[1]|(R.b[0][0]&map[mid][0]&map[mid][1]&R.b[1][1]&L.c[1]);
        return tmp;
    }
    void build(int l,int r,int pos){
        if(l==r){tree[pos].b[1][1]=tree[pos].b[0][0]=1;return;}
        int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
        build(l,mid,lson),build(mid+1,r,rson);
    }
    void insert(int l,int r,int pos,int L,int num,bool v){
        if(l==r){
            if(num==2)tree[pos].b[0][1]=tree[pos].b[1][0]=tree[pos].c[0]=tree[pos].c[1]=map2[l]=v;
            else map[l][num]=v;return;
        }
        int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
        if(mid<L)insert(mid+1,r,rson,L,num,v);
        else insert(l,mid,lson,L,num,v);
        tree[pos]=push_up(tree[lson],tree[rson],mid);
    }
    Node query(int l,int r,int pos,int L,int R){
        if(l>=L&&r<=R)return tree[pos];
        int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
        if(mid<L)return query(mid+1,r,rson,L,R);
        else if(mid>=R)return query(l,mid,lson,L,R);
        else return push_up(query(l,mid,lson,L,R),query(mid+1,r,rson,L,R),mid);
    }
    int main(){
        scanf("%d",&n),build(1,n,1);
        while(scanf("%s",op)&&op[0]!='E'){
            scanf("%d%d%d%d",&r1,&c1,&r2,&c2),r1--,r2--;
            if(c1>c2)swap(c1,c2),swap(r1,r2);
            if(op[0]=='A'){
                Node a=query(1,n,1,1,c1),b=query(1,n,1,c2,n),c=query(1,n,1,c1,c2);
                if(c.b[r1][r2]|(a.c[1]&c.b[!r1][r2])|(b.c[0]&c.b[r1][!r2])|(b.c[0]&a.c[1]&c.b[!r1][!r2]))puts("Y");
                else puts("N");
            }
            else{
                if(r1==r2)jy=(r1==1);
                else jy=2;
                insert(1,n,1,c1,jy,op[0]=='O');
            }
        }
    }
  • 相关阅读:
    C# 迭代器.NET实现—IEnumerable和IEnumerator
    Excel、CSV文件处理
    C# 读写ini文件
    SCARA——OpenGL入门学习五六(三维变换、动画)
    GDI与OpenGL与DirectX之间的区别
    SCARA——OpenGL入门学习四(颜色)
    SCARA——OpenGL入门学习三
    SQLite数据库表是否存在
    数据库SQL语句单引号、双引号的用法
    C# 委托与事件
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6536953.html
Copyright © 2011-2022 走看看