Bzoj1018[SHOI2008]堵塞的交通traffic(线段树)

这题需要维护连通性,看到有连接删除,很容易直接就想LCT了。然而这题点数20w操作10w,LCT卡常估计过不去。看到这个东西只有两行,考虑能否用魔改后的线性数据结构去维护。我想到了线段树。

考虑如果两个点相连,能有几种情况。有一种是两个点直接经过中间的路径相连,这个满足合并性,很容易维护。然后就是某一个点(或两个点)从两边绕了一下,由上到下或由下到上,然后走中间了路径相连的情况。

(借用官方的一张图)

对于第二种情况,考虑它应该是是什么样子的。注意这张图总共就两行,那么这个东西一定是从上面一行走横着的边到某一个位置,走一条竖着的边,然后再到下面连续走横着的边。

所以,我们对于某一个位置能否到达其对应位置,只需要维护其横向能到达的最远位置,以及这两个位置之间有没有纵向边即可。

确定位置只需要维护横向连通性,然后线段树二分即可。

横向连通性满足合并性,总向边可以用数量求和,均可以用线段树维护。

于是此题得解。

 

关于实现,我们定义每个区间保存一个Node,其中f[0/1][0/1]表示区间左边的上、下能否到区间右边的上下(0上1下),维护linked[0/1]表示区间(0上1下)是否左右全部联通,同时维护sum表示这个区间纵向边数量的和。

对于每一个位置,维护ver表示是否有纵向边,hor[0/1]表示从位置i有没有到位置i+1的横向边(0上1下)。

合并的话节点直接用左右状态判,和很容易转移。

查询位置的线段树二分,无非就是先向上走再向下走,自行脑补一发即可(不会看代码)。

最终判定的时候用了一下状压,仅能判定上面的点用1,仅能判定下面用2,如果上下联通,则均可判定,用3来表示。

 

最后上代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define debug cout
  6 using namespace std;
  7 const int maxn=1e5+1e2;
  8 
  9 int l[maxn<<3],r[maxn<<3],lson[maxn<<3],rson[maxn<<3],fa[maxn<<3];
 10 int linked[maxn<<3][2],ver[maxn],hor[maxn][2]; 
 11 int sum[maxn<<3];
 12 
 13 struct Node {
 14     int f[2][2];
 15     int* operator [] (const int &x) {
 16         return f[x];
 17     }
 18     Node() {
 19         memset(f,0,sizeof(f));
 20     }
 21 }ns[maxn<<3];
 22 int n,m,cnt;
 23 
 24 inline Node merge(int* h,Node a,Node b) {
 25     Node ret;
 26     ret.f[0][0] = ( a[0][0]&h[0]&b[0][0] ) | ( a[0][1]&h[1]&b[1][0] );
 27     ret.f[1][1] = ( a[1][1]&h[1]&b[1][1] ) | ( a[1][0]&h[0]&b[0][1] );
 28     ret.f[0][1] = ( a[0][0]&h[0]&b[0][1] ) | ( a[0][1]&h[1]&b[1][1] );
 29     ret.f[1][0] = ( a[1][1]&h[1]&b[1][0] ) | ( a[1][0]&h[0]&b[0][0] );
 30     return ret;
 31 }
 32 
 33 inline void build(int pos,int ll,int rr) {
 34     l[pos] = ll , r[pos] = rr;
 35     if( ll == rr ) {
 36         ns[pos][0][0] = ns[pos][1][1] = 1;
 37         linked[pos][0] = linked[pos][1] = 1;
 38         return;
 39     }
 40     const int mid = ( ll + rr ) >> 1;
 41     build(lson[pos]=++cnt,ll,mid);
 42     build(rson[pos]=++cnt,mid+1,rr);
 43     fa[lson[pos]] = fa[rson[pos]] = pos;
 44 }
 45 inline void update_ver(int pos,int tar,int sta) {
 46     if( tar < l[pos] || r[pos] < tar )
 47         return;
 48     if( l[pos] == r[pos] ) {
 49         sum[pos] = ver[tar] = sta;
 50         ns[pos][0][1] = ns[pos][1][0] = sta;
 51         return;
 52     }
 53     const int mid = ( l[pos] + r[pos] ) >> 1;
 54     update_ver(lson[pos],tar,sta);
 55     update_ver(rson[pos],tar,sta);
 56     ns[pos] = merge(hor[mid],ns[lson[pos]],ns[rson[pos]]);
 57     sum[pos] = sum[lson[pos]] + sum[rson[pos]]; // remember this
 58 }
 59 inline void update_hor(int pos,int tar,int at,int sta) {
 60     if( tar < l[pos] || r[pos] < tar )
 61         return;
 62     if( l[pos] == r[pos] ) {
 63         hor[tar][at] = sta;
 64         return;
 65     }
 66     const int mid = ( l[pos] + r[pos] ) >> 1;
 67     update_hor(lson[pos],tar,at,sta);
 68     update_hor(rson[pos],tar,at,sta);
 69     ns[pos] = merge(hor[mid],ns[lson[pos]],ns[rson[pos]]);
 70     linked[pos][0] = linked[lson[pos]][0] & hor[mid][0] & linked[rson[pos]][0],
 71     linked[pos][1] = linked[lson[pos]][1] & hor[mid][1] & linked[rson[pos]][1];
 72 }
 73 inline Node querymid(int pos,int ll,int rr) {
 74     if( !pos )
 75         exit(0);
 76     if( ll <= l[pos] && r[pos] <= rr )
 77         return ns[pos];
 78     const int mid = ( l[pos] + r[pos] ) >> 1;
 79     if( rr <= mid )
 80         return querymid(lson[pos],ll,rr);
 81     if( ll > mid )
 82         return querymid(rson[pos],ll,rr);
 83     return merge(hor[mid],querymid(lson[pos],ll,rr),querymid(rson[pos],ll,rr));
 84 }
 85 inline int queryver(int pos,int ll,int rr) {
 86     if( rr < l[pos] || r[pos] < ll )
 87         return 0;
 88     if( ll <= l[pos] && r[pos] <= rr )
 89         return sum[pos];
 90     return queryver(lson[pos],ll,rr) + queryver(rson[pos],ll,rr);
 91 }
 92 inline int downleft(int pos,int at) {
 93     if( l[pos] == r[pos] )
 94         return l[pos];
 95     const int mid = ( l[pos] + r[pos] ) >> 1;
 96     if( hor[mid][at] && linked[rson[pos]][at] )
 97         return downleft(lson[pos],at);
 98     return downleft(rson[pos],at);
 99 }
100 inline int leftup(int pos,int at) {
101     if( pos == 1 )
102         return 1;
103     if( pos == lson[fa[pos]] )
104         return leftup(fa[pos],at);
105     const int fmid = l[pos] - 1;
106     if( hor[fmid][at] ) {
107         if( linked[lson[fa[pos]]][at] )
108             return leftup(fa[pos],at);
109         return downleft(lson[fa[pos]],at);
110     }
111     return l[pos];
112 }
113 inline int downright(int pos,int at) {
114     if( l[pos] == r[pos] )
115         return r[pos];
116     const int mid = ( l[pos] + r[pos] ) >> 1;
117     if( hor[mid][at] && linked[lson[pos]][at] )
118         return downright(rson[pos],at);
119     return downright(lson[pos],at);
120 }
121 inline int rightup(int pos,int at) {
122     if( pos == 1 )
123         return n;
124     if( pos == rson[fa[pos]] )
125         return rightup(fa[pos],at);
126     const int fmid = r[pos];
127     if( hor[fmid][at] ) {
128         if( linked[rson[fa[pos]]][at] )
129             return rightup(fa[pos],at);
130         return downright(rson[fa[pos]],at);
131     }
132     return r[pos];
133 }
134 inline int findpos(int pos,int tar) {
135     while( l[pos] != r[pos] ) {
136         const int mid = ( l[pos] + r[pos] ) >> 1;
137         if( tar <= mid )
138             pos = lson[pos];
139         else
140             pos = rson[pos];
141     }
142     return pos;
143 }
144 
145 inline void solve_case(int x,int y,int xx,int yy) {
146     int sta = y , stb = yy , ans = 0;
147     const int mostl = max( leftup(findpos(1,x),0) , leftup(findpos(1,x),1) );
148     const int mostr = min( rightup(findpos(1,xx),0) , rightup(findpos(1,xx),1) );
149     if( queryver(1,mostl,x) )
150         sta = 3;
151     if( queryver(1,xx,mostr) )
152         stb = 3;
153     Node md = querymid(1,x,xx);
154     for(int i=0;i<2;i++)
155         for(int j=0;j<2;j++)
156             if( ( sta & (1<<i) ) && ( stb & (1<<j) ) )
157                 ans |= md[i][j];
158     puts(ans?"Y":"N");
159 }
160 
161 char com[10];
162 int x,y,xx,yy;
163 
164 inline void explain() {
165     int sta = *com == 'O';
166     if( y == yy )
167         update_hor(1,x,y-1,sta);
168     else if( x == xx ) {
169         update_ver(1,x,sta);
170     }
171 }
172 
173 int main() {
174     scanf("%d",&n);
175     build(cnt=1,1,n);
176     int cc = 0;
177     while( scanf("%s",com) == 1 && *com != 'E' ) {
178         scanf("%d%d%d%d",&y,&x,&yy,&xx);
179         if( x > xx )
180             swap(x,xx) , swap(y,yy);
181         if( *com == 'A' )
182             solve_case(x,y,xx,yy);
183         else
184             explain();
185     }
186     
187     return 0;
188     
189 }

 

转载于:https://www.cnblogs.com/Cmd2001/p/8127620.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值