bzoj1018: [SHOI2008]堵塞的交通traffic 线段树区间合并

70 篇文章 0 订阅
37 篇文章 0 订阅

线段树经典题目。判断点的连通性时用分类讨论,x,y,z分别表示横轴 纵轴 斜边 方向的联通性。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;
#define maxn 110000
struct state
{
    bool x1,x2,y1,y2,z1,z2;
};
struct node
{
    int l,r,m;
    state s;
}seg[maxn<<2];
bool edge[maxn<<2][2];
int c;
void build(int l,int r,int rt)
{
    seg[rt].l=l;
    seg[rt].r=r;
    seg[rt].m=(l+r)>>1;
    int m=seg[rt].m;
    if(l==r)
    {
        seg[rt].s.x1=seg[rt].s.x2=1;
        return;
    }
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
}

state join(state ls,state rs,int mid)
{
    state tmp;
    tmp.x1=(ls.z1&&edge[mid][1]&&rs.z2)||(ls.x1&&edge[mid][0]&&rs.x1);
    tmp.x2=(ls.x2&&edge[mid][1]&&rs.x2)||(ls.z2&&edge[mid][0]&&rs.z1);
    tmp.y1=ls.y1||(ls.x1&&edge[mid][0]&&rs.y1&&edge[mid][1]&&ls.x2);
    tmp.y2=rs.y2||(rs.x1&&edge[mid][0]&&ls.y2&&edge[mid][1]&&rs.x2);
    tmp.z1=(ls.z1&&edge[mid][1]&&rs.x2)||(ls.x1&&edge[mid][0]&&rs.z1);
    tmp.z2=(ls.x2&&edge[mid][1]&&rs.z2)||(ls.z2&&edge[mid][0]&&rs.x1);
    return tmp;
}
void update(int x1,int y1,int x2,int y2,int rt,int ord)
{
    if(x1==seg[rt].l &&x2==seg[rt].r)
    {
        if(x1==x2&&abs(y1-y2)==1)
        {
            seg[rt].s.y1=seg[rt].s.y2=seg[rt].s.z1=seg[rt].s.z2=ord;
        }
        if(x1==x2-1)
        {
            seg[rt].s=join(seg[rt<<1].s,seg[rt<<1|1].s,seg[rt<<1].r);
        }
        return;
    }
    if(x2<=seg[rt].m)
    {
        update(x1,y1,x2,y2,rt<<1,ord);
    }
    else if(x1>seg[rt].m)
    {
        update(x1,y1,x2,y2,rt<<1|1,ord);
    }
    seg[rt].s=join(seg[rt<<1].s,seg[rt<<1|1].s,seg[rt].m);
}
state get(int rt,int l,int r)
{
    if(l==seg[rt].l && seg[rt].r==r)
        return seg[rt].s;
    if(r<=seg[rt].m)
        return get(rt<<1,l,r);
    if(seg[rt].m<l)
        return get(rt<<1|1,l,r);
    return join(get(rt<<1,l,seg[rt].m),get(rt<<1|1,seg[rt].m+1,r),seg[rt].m);
}
bool query(int x1,int y1,int x2,int y2)
{
    if(x1==x2&&y1==y2) return true;
    if(x1>x2)
    {
        swap(x1,x2);
        swap(y1,y2);
    }

    state s1,s2,s3;

    if(x1>1) s1=get(1,1,x1-1);

    s2=get(1,x1,x2);

    if(x2<c) s3=get(1,x2+1,c);

    if(x1==x2&&s2.y1)return true;

    if(x1!=x2&&((y1==1&&y2==1&&s2.x2)||(y1==1&&y2==0&&s2.z2)||(y1==0&&y2==1&&s2.z1)||(y1==0&&y2==0&&s2.x1)))
        return true;
    if(x1>1&&edge[x1-1][0]&&edge[x1-1][1]&&s1.y2&&((x1==x2)||(y1==1&&y2==1&&s2.z1)||(y1==1&&y2==0&&s2.x1)||(y1==0&&y2==1&&s2.x2)||(y1==0&&y2==0&&s2.z2)))
        return true;
    if(x2<c&&edge[x2][0]&&edge[x2][1]&&s3.y1&&((x1==x2)||(y1==1&&y2==1&&s2.z2)||(y1==1&&y2==0&&s2.x2)||(y1==0&&y2==1&&s2.x1)||(y1==0&&y2==0&&s2.z1)))
        return true;
    if(x1>1&&x2<c&&edge[x1-1][0]&&edge[x1-1][1]&&s1.y2&&edge[x2][0]&&edge[x2][1]&&s3.y1&&((x1==x2)||(y1==1&&y2==1&&s2.x1)||(y1==1&&y2==0&&s2.z1)||(y1==0&&y2==1&&s2.z2)||(y1==0&&y2==0&&s2.x2)))
        return true;

        return false;
}
int main()
{
    scanf("%d",&c);
    build(1,c,1);
    int r1,c1,r2,c2;
    char st[20];
    while(scanf("%s",st)&&st[0]!='E')
    {
        scanf("%d%d%d%d",&r1,&c1,&r2,&c2);

        if(st[0]=='O')
        {
             if(c1>c2)
        {
            swap(c1,c2);
            swap(r1,r2);
        }
            if(c1==c2-1)
                edge[c1][r1-1]=true;
            update(c1,r1-1,c2,r2-1,1,1);
        }
        if(st[0]=='C')
        {
             if(c1>c2)
        {
            swap(c1,c2);
            swap(r1,r2);
        }
            if(c1==c2-1)
                edge[c1][r1-1]=false;
            update(c1,r1-1,c2,r2-1,1,0);
        }
          if(st[0]=='A')
            printf("%c\n",query(c1,r1-1,c2,r2-1)?'Y':'N');
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值