BZOJ 1018: [SHOI2008]堵塞的交通traffic

20 篇文章 0 订阅

线段树有这种姿势啊。。是我太菜了。。。

一开始简直被吓呆了,总感觉要写好多。。很烦。。。对着某个题解盯了半天才敢写QAQ
然后我发现很赞啊
幸好发现了这篇233 参考了他的写法 (我基本上是抄他的

用一个数组 a[i][j] ,维护从 x 节点最左端的i行能否到最右端的 j 行。

另一个数组v[i] v[0] 表示 x 节点最右端的点能不能从右面绕到另外一行。v[1]代表最左端的点能不能从左面绕到另外一行。

转移大概就是各种讨论吧,画画图什么的….

然后我就在2k左右的代码就解决这题啦~ 时间也很可观

大家也可以参考参考我的代码QAQ,写的短的感觉真不错233

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+3,inf=1e9+7;
inline 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<<1)+(x<<3)+(ch^48); ch=getchar();}
    return x*f;
}
struct mt{bool a[2][2],v[2];}s[N]; int n;
mt upd(mt s1,mt s2,bool b[]){
    mt g;
    for(int i=0;i<2;++i)for(int j=0;j<2;++j)
        g.a[i][j]= s1.a[i][0] && b[0] && s2.a[0][j] || s1.a[i][1] && b[1] && s2.a[1][j];
    g.v[0]=s1.v[0] || s1.a[0][0] && b[0] && s2.v[0] && s1.a[1][1] && b[1];
    g.v[1]=s2.v[1] || s2.a[0][0] && b[0] && s1.v[1] && s2.a[1][1] && b[1];
    return g;
}
bool b[N][2]; int X1,Y1,X2,Y2;
mt access(int x,int l,int r,int ql,int qr){
    if(l==ql && r==qr) return s[x];
    int mid=l+r>>1;
    if(qr<=mid) return access(x<<1,l,mid,ql,qr);
    if(ql>mid) return access(x<<1|1,mid+1,r,ql,qr);
    return upd(access(x<<1,l,mid,ql,mid),access(x<<1|1,mid+1,r,mid+1,qr),b[x]);
}
void bulid(int x,int l,int r){
    if(l==r) s[x].a[0][0]=s[x].a[1][1]=1;
    else {int mid=l+r>>1; bulid(x<<1,l,mid),bulid(x<<1|1,mid+1,r);}
}
void change(int x,int l,int r,int u){
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    if(X1==X2 && Y1==mid){
        b[x][X1]=u; s[x]=upd(s[lc],s[rc],b[x]);
    }
    else if(l==r) s[x].a[0][1]=s[x].a[1][0]=s[x].v[0]=s[x].v[1]=u;
    else{
        if(Y2<=mid) change(lc,l,mid,u); else change(rc,mid+1,r,u);
        s[x]=upd(s[lc],s[rc],b[x]);
    }
}
void ask(){
    mt L=access(1,1,n,1,Y1),R=access(1,1,n,Y2,n),M=access(1,1,n,Y1,Y2);
    bool g=0;
    for(int i=0;i<2;++i)for(int j=0;j<2;++j)
        if(M.a[i][j] && (i==X1||L.v[1]) && (j==X2||R.v[0])){g=1; break;}
    puts(g?"Y":"N");
}
int main(){
    n=read(); bulid(1,1,n);
    while(1){
        char c[10]; scanf("%s",c);
        if(c[0]=='E')return 0;
        X1=read()-1,Y1=read(),X2=read()-1,Y2=read();
        if(Y1>Y2) swap(X1,X2),swap(Y1,Y2);
        if(c[0]=='A') ask();
        else change(1,1,n,c[0]=='O');
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值