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 }