当前位置: 代码迷 >> 综合 >> bzoj 1018 堵塞的交通traffic (线段树)
  详细解决方案

bzoj 1018 堵塞的交通traffic (线段树)

热度:0   发布时间:2023-12-17 03:23:58.0

题意:

思路:

参考博客:https://www.cnblogs.com/MashiroSky/p/5973686.html
        非常非常难写的线段树,不仅难想还难写。
        首先,这个线段树维护的是什么,是该区域四个顶点的连通性
这里写图片描述
       比如维护一个宽度为6的区域,我们维护的就是图中1,2,3,4的连通性。
       然后考虑怎么合并两个区间,因为合并的时候,两个子区间都是已经内部联通好的了,因为我们并不在意具体路径,只要能联通就可以了,所以,合并区间就相当于这样:
这里写图片描述
       其中1234为左儿子的区间,5678为右儿子的区间,我们发现想要合并两个区间,就需要知道25,47的连通性,也就是mid和mid+1的连通性。
       事实上,最后我们维护了8个连通性,分别是1和2,1和3,1和4,2和3,3和4,2和4,mid和mid+1的第一行连通性,mid和mid+1的第二行连通性。
       具体更新的时候,两个格子的相对位置是需要分类讨论的。而pushup的操作大家在理解连通性以后就很好理解了。
       最后想想怎么查询,比如我们询问上图2,7的连通性,其中2可能需要先向左跑,然后再跑到7(上面贴的dalao的博客有更详细的解释),正是因为这种情况,我们就需要把区间切成3部分(就是三个区间),第一部分是1到c1,第二部分是c1到c2,第三部分是c2到n。这样就能处理掉上面说的跑法了。

错误及反思:

代码:

代码也参考了大佬的代码(其实最后都改得没啥区别了),说句实话,没这位dalao的代码我根本写不出来,太难写了

#include<bits/stdc++.h>
using namespace std;
const int N = 201000;
#define ls rt<<1
#define rs rt<<1|1/*U:第一行mid,mid+1两列之间是否联通D:第二行mid,mid+1两列之间是否联通l:s1,s3是否联通r:s2,s4是否联通u:s1,s2是否联通d:s3,s4是否联通q:s1,s4是否联通p:s3,s2是否联通*/int n;
char s[10];
struct Segtree{int U,D,l,r,u,d,q,p;
}seg[N<<2];void pushup(Segtree &rt,Segtree l,Segtree r){rt.l=l.l||(l.u&&rt.U&&r.l&&rt.D&&l.d);rt.r=r.r||(r.u&&rt.U&&l.r&&rt.D&&r.d);rt.u=(l.u&&rt.U&&r.u)||(l.q&&rt.D&&r.p);rt.d=(l.d&&rt.D&&r.d)||(l.p&&rt.U&&r.q);rt.p=(l.p&&rt.U&&r.u)||(l.d&&rt.D&&r.p);rt.q=(l.q&&rt.D&&r.d)||(l.u&&rt.U&&r.q);
}void build(int l,int r,int rt){if(l==r){seg[rt].U=seg[rt].D=seg[rt].u=seg[rt].d=1;return ;}int m=(l+r)/2;build(l,m,ls);build(m+1,r,rs);
}void update1(int x,int p,int l,int r,int rt){if(l==r){seg[rt].l=seg[rt].r=seg[rt].p=seg[rt].q=p;return ;}int m=l+r>>1;if(m>=x) update1(x,p,l,m,ls);else update1(x,p,m+1,r,rs);pushup(seg[rt],seg[ls],seg[rs]);
}void update2(int x,int w,int p,int l,int r,int rt){int m=l+r>>1;if(m==x){if(w==1) seg[rt].U=p;else seg[rt].D=p;pushup(seg[rt],seg[ls],seg[rs]);return ;}if(m>=x) update2(x,w,p,l,m,ls);else update2(x,w,p,m+1,r,rs);pushup(seg[rt],seg[ls],seg[rs]);
}Segtree query(int L,int R,int l,int r,int rt) {if (L<=l && r<=R) return seg[rt];int m=l+r>>1;if (R<=m) return query(L,R,l,m,ls);else if (L>m) return query(L,R,m+1,r,rs);else {Segtree x=seg[rt];pushup(x,query(L,R,l,m,ls),query(L,R,m+1,r,rs));return x;}
}int main(){scanf("%d",&n);build(1,n,1);while(scanf("%s",s)){if(s[0]=='E') break;int r1,c1,r2,c2;scanf("%d%d%d%d",&r1,&c1,&r2,&c2);if(c1>c2) swap(r1,r2),swap(c1,c2);if(s[0]=='O'){if(c1==c2) update1(c1,1,1,n,1);else update2(c1,r1,1,1,n,1);}else if(s[0]=='C'){if(c1==c2) update1(c1,0,1,n,1);else update2(c1,r1,0,1,n,1);}else{int ans;Segtree l=query(1,c1,1,n,1),x=query(c1,c2,1,n,1),r=query(c2,n,1,n,1);if(r1==1&&r2==1)ans=x.u||(l.r&&x.p)||(r.l&&x.q)||(l.r&&x.d&&r.l);if(r1==2&&r2==2)ans=x.d||(l.r&&x.q)||(r.l&&x.p)||(l.r&&x.u&&r.l);if(r1==1&&r2==2)ans=x.q||(l.r&&x.d)||(r.l&&x.u)||(l.r&&x.p&&r.l);if(r1==2&&r2==1)ans=x.p||(l.r&&x.u)||(r.l&&x.d)||(l.r&&x.q&&r.l);if(ans) printf("Y\n");else printf("N\n");}}
}
  相关解决方案