[BZOJ1018][SHOI2008]堵塞的交通traffic(线段树维护连通性)

题目描述

传送门

题解

『郁闷』现在写一道题都要以半天为单位计算时间了= =
数据结构是一个要填的大坑= =之前学过的也只能算是草草学过,没有大量的练习来填坑是不会有提高的= =光打模板题没什么意思= =那么考验码力的时候到了= =

这道题让我明白了怎样用线段树维护连通性。就这道题来说,线段树中的每一个结点都用六个结构体维护一个矩形的连通性(分别是左上右上,左下右下,左上右下,左下右上,左上左下和右上右下),然后update和query的时候会有一些非常奇怪的合并。
主要是想明白一点:判断(x1,y1)(x2,y2)是否连通,所求的路径不一定是在[y1,y2]这个区间里,有可能在区间外面绕一圈又回来了,所以每次query其实需要查询3个区间,然后取一些奇怪的并集。
思路是很好懂的,但是细节十分吃屎= =比如说怎样考虑使每一种情况不重不漏,思维逻辑的缜密十分重要。
再有就是代码能力。刚开始的时候想都没想怒写400行代码,然后发现TLE了。其实是写了很多冗余的东西。后来考虑合并和简化之后又WA一组,最终是一个手残错误= =可见有了思路能否实现也是一个大问题。

代码

贴上可怕的7k代码,TLE

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int max_n=1e5+5;
const int max_tree=max_n*5;

int n,x1,y1,x2,y2;
struct hp{
    int luru,lurd,ldru,ldrd,luld,rurd;
}tree[max_tree];
struct hq{
    int l,r;
}num[max_tree];
bool up[max_n],down[max_n],list[max_n];

char opt[10];


inline void update(int now){

    bool a,b;

    //luru
    a=tree[now<<1].luru && tree[now<<1|1].luru && up[ num[now<<1].r ];
    b=tree[now<<1].lurd && tree[now<<1|1].ldru && down[ num[now<<1].r ];
    tree[now].luru=a||b;

    //lurd
    a=tree[now<<1].luru && tree[now<<1|1].lurd && up[ num[now<<1].r ];
    b=tree[now<<1].lurd && tree[now<<1|1].ldrd && down[ num[now<<1].r ];
    tree[now].lurd=a||b;

    //ldru
    a=tree[now<<1].ldru && tree[now<<1|1].luru && up[ num[now<<1].r ];
    b=tree[now<<1].ldrd && tree[now<<1|1].ldru && down[ num[now<<1].r ];
    tree[now].ldru=a||b;

    //ldrd
    a=tree[now<<1].ldru && tree[now<<1|1].lurd && up[ num[now<<1].r ];
    b=tree[now<<1].ldrd && tree[now<<1|1].ldrd && down[ num[now<<1].r ];
    tree[now].ldrd=a||b;

    //luld
    a=tree[now<<1].luld;
    b=tree[now<<1].luru && tree[now<<1].ldrd && tree[now<<1|1].luld && up[ num[now<<1].r ] && down[ num[now<<1].r ];
    tree[now].luld=a||b;

    //rurd
    a=tree[now<<1|1].rurd;
    b=tree[now<<1|1].luru && tree[now<<1|1].ldrd && tree[now<<1].rurd && up[ num[now<<1].r ] && down[ num[now<<1].r ];
    tree[now].rurd=a||b;
}

inline void build(int now,int l,int r){
    int mid=(l+r)>>1;
    num[now].l=l; num[now].r=r;

    if (l==r){
        tree[now].luru=true;
        tree[now].lurd=false;
        tree[now].ldru=false;
        tree[now].ldrd=true;
        tree[now].luld=false;
        tree[now].rurd=false;

        return;
    }

    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);

    update(now);
}

inline void change(int now,int l,int r,int x){
    int mid=(l+r)>>1;

    if (l==r){
        tree[now].luru=true;
        tree[now].lurd=list[l];
        tree[now].ldru=list[l];
        tree[now].ldrd=true;
        tree[now].luld=list[l];
        tree[now].rurd=list[l];

        return;
    }

    if (x<=mid)
      change(now<<1,l,mid,x);
    else
      change(now<<1|1,mid+1,r,x);

    update(now);
}

inline bool query(int now,int l,int r,int lrange,int rrange,int order){
    int mid=(l+r)>>1;

    if (lrange<=l&&r<=rrange){

        switch(order){
            case 1:{
                return tree[now].luru;
                break;
            }
            case 2:{
                return tree[now].ldrd;
                break;
            }
            case 3:{
                return tree[now].lurd;
                break;
            }
            case 4:{
                return tree[now].ldru;
                break;
            }
            case 5:{
                return tree[now].luld;
                break;
            }
            case 6:{
                return tree[now].rurd;
                break;
            }
        }

    }

    bool pd1=false,pd2=false;
    bool al,bl,cl,dl,el,fl,ar,br,cr,dr,er,fr;

    if (lrange<=mid){

        pd1=true;
        al=query(now<<1,l,mid,lrange,rrange,1);
        bl=query(now<<1,l,mid,lrange,rrange,2);
        cl=query(now<<1,l,mid,lrange,rrange,3);
        dl=query(now<<1,l,mid,lrange,rrange,4);
        el=query(now<<1,l,mid,lrange,rrange,5);
        fl=query(now<<1,l,mid,lrange,rrange,6);

    }
    if (mid+1<=rrange){

        pd2=true;
        ar=query(now<<1|1,mid+1,r,lrange,rrange,1);
        br=query(now<<1|1,mid+1,r,lrange,rrange,2);
        cr=query(now<<1|1,mid+1,r,lrange,rrange,3);
        dr=query(now<<1|1,mid+1,r,lrange,rrange,4);
        er=query(now<<1|1,mid+1,r,lrange,rrange,5);
        fr=query(now<<1|1,mid+1,r,lrange,rrange,6);

    }


    if (pd1&&pd2){

        switch(order){
            case 1:{
                return al&&ar&&up[ num[now<<1].r ] || cl&&dr&&down[ num[now<<1].r ];
                break;
            }
            case 2:{
                return dl&&cr&&up[ num[now<<1].r ] || bl&&br&&down[ num[now<<1].r ];
                break;
            }
            case 3:{
                return al&&cr&&up[ num[now<<1].r ] || cl&&br&&down[ num[now<<1].r ];
                break;
            }
            case 4:{
                return dl&&ar&&up[ num[now<<1].r ] || bl&&dr&&down[ num[now<<1].r ];
                break;
            }
            case 5:{
                return el || al&&bl&&er&&up[ num[now<<1].r ]&&down[ num[now<<1].r ];
                break;
            }
            case 6:{
                return fr || ar&&br&&fl&&up[ num[now<<1].r ]&&down[ num[now<<1].r ];
                break;
            }
        }

    }

    if (pd1&&!pd2){

        switch(order){
            case 1:{
                return al;
                break;
            }
            case 2:{
                return bl;
                break;
            }
            case 3:{
                return cl;
                break;
            }
            case 4:{
                return dl;
                break;
            }
            case 5:{
                return el;
                break;
            }
            case 6:{
                return fl;
                break;
            }
        }

    }

    if (!pd1&&pd2){

        switch (order){
            case 1:{
                return ar;
                break;
            }
            case 2:{
                return br;
                break;
            }
            case 3:{
                return cr;
                break;
            }
            case 4:{
                return dr;
                break;
            }
            case 5:{
                return er;
                break;
            }
            case 6:{
                return fr;
                break;
            }
        }

    }

    if (!pd1&&!pd2) return false;
}

inline bool ask(int x1,int y1,int x2,int y2){

    //1:luru 2:ldrd 3:lurd 4:ldru 5:luld 6:rurd

    bool a,b,c,d,e,f;

    a=query(1,1,n,x1,x2,1);
    b=query(1,1,n,x1,x2,2);
    c=query(1,1,n,x1,x2,3);
    d=query(1,1,n,x1,x2,4);

    e=query(1,1,n,1,x1,6);
    f=query(1,1,n,x2,n,5);

    if (y1==0&&y2==0){

        return a || d&&e || c&&f || b&&e&&f;

    }
    if (y1==1&&y2==1){

        return b || c&&e || d&&f || a&&e&&f;

    }
    if (y1==0&&y2==1){

        return c || a&&f || b&&e || d&&e&&f;

    }
    if (y1==1&&y2==0){

        return d || a&&e || b&&f || c&&e&&f;

    }

}

int main(){
// freopen("input.txt","r",stdin);

    scanf("%d",&n);

    memset(up,0,sizeof(up));
    memset(down,0,sizeof(down));

    build(1,1,n);

    while (scanf("%s",opt)!=EOF){

        if (opt[0]=='E') break;

        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        swap(x1,y1);
        swap(x2,y2);
        if (x1>x2){
            swap(x1,x2);
            swap(y1,y2);
        }
        --y1; --y2;
// cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl;

        if (opt[0]=='O'){
            if (x1==x2){
                list[x1]=true;

                change(1,1,n,x1);
            }
            else{
                if (y1==0){
                    up[x1]=true;

                    change(1,1,n,x1);
                    change(1,1,n,x2);
                } 
                else{
                    down[x1]=true;

                    change(1,1,n,x1);
                    change(1,1,n,x2);
                } 
            }
        }

        if (opt[0]=='C'){
            if (x1==x2){
                list[x1]=false;

                change(1,1,n,x1);
            }
            else{
                if (y1==0){
                    up[x1]=false;

                    change(1,1,n,x1);
                    change(1,1,n,x2);
                } 
                else{
                    down[x1]=false;

                    change(1,1,n,x1);
                    change(1,1,n,x2);
                } 
            }
        }

        if (opt[0]=='A'){
            bool ans=ask(x1,y1,x2,y2);
            if (ans) printf("Y\n");
            else printf("N\n");
        }
    }

    /* for (int i=1;i<n;++i) printf("%d%c",up[i]," \n"[i==n-1]); for (int i=1;i<n;++i) printf("%d%c",down[i]," \n"[i==n-1]); for (int i=1;i<=n;++i) printf("%d%c",list[i]," \n"[i==n]); */

}

AC代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int max_n=1e5+5;
const int max_tree=max_n*5;

int n,x1,y1,x2,y2;
struct hp{
    int luru,lurd,ldru,ldrd,luld,rurd;
}tree[max_tree];
struct hq{
    bool a,b,c,d,e,f;
};
int num[max_tree];
bool up[max_n],down[max_n],list[max_n];

char opt[10];


inline void update(int now){

    bool a,b;

    //luru
    a=tree[now<<1].luru && tree[now<<1|1].luru && up[ num[now<<1] ];
    b=tree[now<<1].lurd && tree[now<<1|1].ldru && down[ num[now<<1] ];
    tree[now].luru=a||b;

    //lurd
    a=tree[now<<1].luru && tree[now<<1|1].lurd && up[ num[now<<1] ];
    b=tree[now<<1].lurd && tree[now<<1|1].ldrd && down[ num[now<<1] ];
    tree[now].lurd=a||b;

    //ldru
    a=tree[now<<1].ldru && tree[now<<1|1].luru && up[ num[now<<1] ];
    b=tree[now<<1].ldrd && tree[now<<1|1].ldru && down[ num[now<<1] ];
    tree[now].ldru=a||b;

    //ldrd
    a=tree[now<<1].ldru && tree[now<<1|1].lurd && up[ num[now<<1] ];
    b=tree[now<<1].ldrd && tree[now<<1|1].ldrd && down[ num[now<<1] ];
    tree[now].ldrd=a||b;

    //luld
    a=tree[now<<1].luld;
    b=tree[now<<1].luru && tree[now<<1].ldrd && tree[now<<1|1].luld && up[ num[now<<1] ] && down[ num[now<<1] ];
    tree[now].luld=a||b;

    //rurd
    a=tree[now<<1|1].rurd;
    b=tree[now<<1|1].luru && tree[now<<1|1].ldrd && tree[now<<1].rurd && up[ num[now<<1] ] && down[ num[now<<1] ];
    tree[now].rurd=a||b;
}

inline void build(int now,int l,int r){
    int mid=(l+r)>>1;
// cout<<now<<endl;

    if (l==r){
        tree[now].luru=true;
        tree[now].lurd=false;
        tree[now].ldru=false;
        tree[now].ldrd=true;
        tree[now].luld=false;
        tree[now].rurd=false;
        num[now]=r; 

        return;
    }

    num[now]=r;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);

    update(now);
}

inline void change(int now,int l,int r,int x){
    int mid=(l+r)>>1;

    if (l==r){
        tree[now].luru=true;
        tree[now].lurd=list[l];
        tree[now].ldru=list[l];
        tree[now].ldrd=true;
        tree[now].luld=list[l];
        tree[now].rurd=list[l];

        return;
    }

    if (x<=mid)
      change(now<<1,l,mid,x);
    else
      change(now<<1|1,mid+1,r,x);

    update(now);
}

inline hq query(int now,int l,int r,int lrange,int rrange){
    int mid=(l+r)>>1;

    hq ans;
    hq L,R;
    bool pd1=false,pd2=false;

    if (lrange<=l&&r<=rrange)
      return ans=(hq){tree[now].luru,tree[now].ldrd,tree[now].lurd,
                      tree[now].ldru,tree[now].luld,tree[now].rurd};

    if (lrange<=mid){
        pd1=true;
        L=query(now<<1,l,mid,lrange,rrange);
    }
    if (mid+1<=rrange){
        pd2=true;
        R=query(now<<1|1,mid+1,r,lrange,rrange);
    }

    if (pd1&&pd2){

        bool a,b,c,d,e,f;

        a=L.a&&R.a&&up[ num[now<<1] ] || L.c&&R.d&&down[ num[now<<1] ];
        b=L.d&&R.c&&up[ num[now<<1] ] || L.b&&R.b&&down[ num[now<<1] ];
        c=L.a&&R.c&&up[ num[now<<1] ] || L.c&&R.b&&down[ num[now<<1] ];
        d=L.d&&R.a&&up[ num[now<<1] ] || L.b&&R.d&&down[ num[now<<1] ];

        e=L.e || L.a&&L.b&&R.e&&up[ num[now<<1] ]&&down[ num[now<<1] ];
        f=R.f || R.a&&R.b&&L.f&&up[ num[now<<1] ]&&down[ num[now<<1] ]; 

        return ans=(hq){a,b,c,d,e,f};
    }

    if (pd1&&!pd2)
      return ans=(hq){L.a,L.b,L.c,L.d,L.e,L.f};

    if (!pd1&&pd2)
      return ans=(hq){R.a,R.b,R.c,R.d,R.e,R.f};

    if (!pd1&&!pd2) return ans=(hq){false,false,false,false,false,false};
}

inline bool ask(int x1,int y1,int x2,int y2){

    hq now,l,r;

    now=query(1,1,n,x1,x2);
    l=query(1,1,n,1,x1);
    r=query(1,1,n,x2,n);

    if (y1==0&&y2==0)
      return now.a || now.d&&l.f || now.c&&r.e || now.b&&l.f&&r.e;
    if (y1==1&&y2==1)
      return now.b || now.c&&l.f || now.d&&r.e || now.a&&l.f&&r.e;
    if (y1==0&&y2==1)
      return now.c || now.a&&r.e || now.b&&l.f || now.d&&l.f&&r.e; 
    if (y1==1&&y2==0)
      return now.d || now.a&&l.f || now.d&&r.e || now.c&&l.f&&r.e;
}

int main(){
    scanf("%d",&n);

    memset(up,0,sizeof(up));
    memset(down,0,sizeof(down));

    build(1,1,n);
    int cnt=0;

    while (scanf("%s",opt)!=EOF){

        if (opt[0]=='E') break;

        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        swap(x1,y1);
        swap(x2,y2);
        if (x1>x2){
            swap(x1,x2);
            swap(y1,y2);
        }
        --y1; --y2;

        if (opt[0]=='O'){
            if (x1==x2){
                list[x1]=true;

                change(1,1,n,x1);
            }
            else{
                if (y1==0){
                    up[x1]=true;

                    change(1,1,n,x1);
                    change(1,1,n,x2);
                } 
                else{
                    down[x1]=true;

                    change(1,1,n,x1);
                    change(1,1,n,x2);
                } 
            }
        }

        if (opt[0]=='C'){
            if (x1==x2){
                list[x1]=false;

                change(1,1,n,x1);
            }
            else{
                if (y1==0){
                    up[x1]=false;

                    change(1,1,n,x1);
                    change(1,1,n,x2);
                } 
                else{
                    down[x1]=false;

                    change(1,1,n,x1);
                    change(1,1,n,x2);
                } 
            }
        }

        if (opt[0]=='A'){
            cnt++;
            bool ans=ask(x1,y1,x2,y2);
            if (ans) printf("Y\n");
            else printf("N\n");
        }
    }
    return 0;
}

总结

用线段树维护连通性有了新的经验。
对冗余的简化。
码力++

你可能感兴趣的:(线段树,bzoj,SHOI)