bzoj 1018 线段树维护连通性

本题将一道LCT的题特殊化(支持加边和删边,询问图的连通性),将图变成了2×m的网格图,然后就神奇地可以用线段树来维护。

对于每个区间[l,r],维护其四个角落之间的连通性(仅仅通过[l,r]这段的边构建起的连通性)。

查询[l,r]时,先计算出[1,l-1],[l,r],[r+1,c]这三个线段的连通性,然后将[l,r]的四个角变成并查集的4个点,先用[l,r]中的6种关系更新,在看是否可以从左上角的点通过左边区间绕道左下角,以及从右上角通过右边区间绕道右下角,该并的并起来后直接看查询的点是否在一个集合即可。

  1 /**************************************************************
  2     Problem: 1018
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:1472 ms
  7     Memory:2840 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <iostream>
 12 #define maxn 100010
 13 #define AB 1
 14 #define AC 2
 15 #define AD 4
 16 #define BC 8
 17 #define BD 16
 18 #define CD 32
 19 using namespace std;
 20
 21 // a b
 22 // c d
 23
 24 typedef unsigned Stat;
 25
 26 Stat stat[maxn];
 27 int son[maxn][2], ntot, root;
 28
 29 int c;
 30 bool er[3][maxn], ed[maxn];
 31
 32 Stat merge( Stat l, Stat r, int mid ) {
 33     Stat ab = ((l&AB)&&(r&AB)&&er[1][mid]) || ((l&AD)&&(r&BC)&&er[2][mid]) ? AB : 0;
 34     Stat cd = ((l&CD)&&(r&CD)&&er[2][mid]) || ((l&BC)&&(r&AD)&&er[1][mid]) ? CD : 0;
 35     Stat ad = ((l&AB)&&(r&AD)&&er[1][mid]) || ((l&AD)&&(r&CD)&&er[2][mid]) ? AD : 0;
 36     Stat bc = ((l&CD)&&(r&BC)&&er[2][mid]) || ((l&BC)&&(r&AB)&&er[1][mid]) ? BC : 0;
 37     Stat ac = (l&AC) || ((l&AB)&&(l&CD)&&(er[1][mid])&&(er[2][mid])&&(r&AC)) ? AC : 0;
 38     Stat bd = (r&BD) || ((r&AB)&&(r&CD)&&(er[1][mid])&&(er[2][mid])&&(l&BD)) ? BD : 0;
 39     return ab | ac | ad | bc | bd | cd;
 40 }
 41 void update( int nd, int lf, int rg ) {
 42     stat[nd] = merge( stat[son[nd][0]], stat[son[nd][1]], (lf+rg)>>1 );
 43 }
 44 int build( int lf, int rg ) {
 45     if( lf>rg ) return 0;
 46     int nd = ++ntot;
 47     if( lf==rg ) {
 48         stat[nd] = AB | CD;
 49         return nd;
 50     }
 51     int mid = (lf+rg)>>1;
 52     son[nd][0] = build( lf, mid );
 53     son[nd][1] = build( mid+1, rg );
 54     update( nd, lf, rg );
 55     return nd;
 56 }
 57 void modify( int x, int nd, int lf, int rg ) {
 58     if( lf==rg ) {
 59         stat[nd] = AB | CD;
 60         if( ed[lf] )
 61             stat[nd] |= AC | BD | AD | BC;
 62         return;
 63     }
 64     int mid = (lf+rg)>>1;
 65     if( x<=mid ) modify(x,son[nd][0],lf,mid);
 66     else modify(x,son[nd][1],mid+1,rg);
 67     update(nd,lf,rg);
 68 }
 69 Stat query( int L, int R, int nd, int lf, int rg ) {
 70     if( L<=lf&&rg<=R ) return stat[nd];
 71     int mid = (lf+rg)>>1;
 72     if( R<=mid ) return query( L, R, son[nd][0], lf, mid );
 73     if( L>mid ) return query( L, R, son[nd][1], mid+1, rg );
 74     Stat lstat = query( L, R, son[nd][0], lf, mid );
 75     Stat rstat = query( L, R, son[nd][1], mid+1, rg );
 76     return merge(lstat,rstat,mid);
 77 }
 78
 79 int fa[5];
 80 void init() {
 81     for( int i=1; i<=4; i++ ) fa[i]=i;
 82 }
 83 int find( int i ) {
 84     return fa[i]==i ? i : fa[i]=find(fa[i]);
 85 }
 86 void unon( int a, int b ) {
 87     a = find(a);
 88     b = find(b);
 89     fa[a] = b;
 90 }
 91 int main() {
 92     scanf( "%d", &c );
 93     root = build( 1, c );
 94     while(1) {
 95         char ch[10];
 96
 97         scanf( "%s", ch );
 98         if( ch[0]==‘E‘ ) return 0;
 99         int ax, ay, bx, by;
100         scanf( "%d%d%d%d", &ax, &ay, &bx, &by );
101
102         if( ch[0]==‘A‘ ) {
103             if( ay>by ) {
104                 swap( ax, bx );
105                 swap( ay, by );
106             }
107             Stat sl=0, sc=0, sr=0;
108             if( ay>1 ) sl = query(1,ay-1,root,1,c);
109             sc = query(ay,by,root,1,c);
110             if( by<c ) sr = query(by+1,c,root,1,c);
111
112             init();
113             if( sc&AB ) unon( 1, 2 );
114             if( sc&AC ) unon( 1, 3 );
115             if( sc&AD ) unon( 1, 4 );
116             if( sc&BC ) unon( 2, 3 );
117             if( sc&BD ) unon( 2, 4 );
118             if( sc&CD ) unon( 3, 4 );
119             if( (sl&BD) && er[1][ay-1] && er[2][ay-1] ) unon( 1, 3 );
120             if( (sr&AC) && er[1][by]   && er[2][by]   ) unon( 2, 4 );
121
122             bool ok = false;
123             if( ax==1 && bx==1 ) {
124                 ok = find( 1 ) == find( 2 );
125             } else if( ax==1 && bx==2 ) {
126                 ok = find( 1 ) == find( 4 );
127             } else if( ax==2 && bx==1 ) {
128                 ok = find( 3 ) == find( 2 );
129             } else if( ax==2 && bx==2 ) {
130                 ok = find( 3 ) == find( 4 );
131             }
132
133             printf( "%s\n", ok ? "Y" : "N" );
134         } else {
135             bool *p;
136             if( ax==bx ) {
137                 p = &er[ax][min(ay,by)];
138             } else {
139                 p = &ed[ay];
140             }
141             *p = ch[0]==‘O‘;
142             modify( ay, root, 1, c );
143             if( ay!=by )
144                 modify( by, root, 1, c );
145         }
146     }
147 }

时间: 2024-10-18 14:51:47

bzoj 1018 线段树维护连通性的相关文章

BZOJ 1018 线段树维护图的连通性问题

思路: 我们可以搞一棵线段树 对于一段区间有6种情况需要讨论 左上右下.左上右上.左下右下.左下右上 这四种比较好维护 用左上右下举个例子吧 就是左儿子的左上右下&左区间到右区间下面有路&右儿子的左下右下 或者是左儿子的左上右上&左区间到右区间上面有路&右儿子的左上右下 还有两种  区间的左(右)端点上下能不能联通 需要维护 这种就是左儿子的上下连通或(左上右上&左上右下&左到右两条路都联通&右儿子的上下联通) (假设c1<c2) 最后要查的是

BZOJ 1018 线段树维护图连通性

用8个bool维护即可分别为LURU,LURD,LDRU,LDRD,LULD,RURD,Side[1],Side[2]即可. Side表示这一块有没有接到右边.Merge一下就可以了.码农题,WA了一次,发现未初始化,就AC了.. 1 #include <cstdio> 2 inline int Min(int x,int y) {return x>y?y:x;} 3 inline void Swap(int &x,int &y) {int t=x;x=y;y=t;} 4

[BZOJ 3995] [SDOI2015] 道路修建 【线段树维护连通性】

题目链接:BZOJ - 3995 题目分析 这道题..是我悲伤的回忆.. 线段树维护连通性,与 BZOJ-1018 类似,然而我省选之前并没有做过  1018,即使它在 ProblemSet 的第一页. 更悲伤的是,这道题有 40 分的暴力分,写个 Kruskal 就可以得到,然而我写了个更快的 DP . 这本来没有什么问题,然而我的 DP 转移少些了一种情况,于是...爆零.没错,省选前20名可能就我没有得到这 40 分? 不想再多说什么了...希望以后不要再这样 SB 了,如果以后还有机会的

bzoj 4127 线段树维护绝对值之和

因为d>=0,所以一个位置的数只会单调不降并且只会有一次穿过0. 用这个性质,我们我可在线段树中记录正数负数的个数和和,以及最大的负数以及答案. 修改操作:如果当前最大负数+d<=0,那么就直接加到懒惰标记中,否则就暴力向下传递. 因为每个节点最多被额外访问该区间负数个数次,所以所有点总共会被额外访问O(nlogn)次,在加上修改操作和询问操作的普通访问O(mlogn)次,所以时间复杂度是有保证的. 谢谢mhy12345的讲解. 1 /*****************************

[BZOJ 1018] [SHOI2008] 堵塞的交通traffic 【线段树维护联通性】

题目链接:BZOJ - 1018 题目分析 这道题就说明了刷题少,比赛就容易跪..SDOI Round1 Day2 T3 就是与这道题类似的..然而我并没有做过这道题.. 这道题是线段树维护联通性的经典模型. 我们线段树的一个节点表示一个区间的联通性,有 6 个 bool 值,表示这个区间的 4 个角上的点之间的联通性. 然后用两个子区间的联通性和两个子区间之间的连边情况合并出整个区间的联通性. 修改某条边时,先在边的数组中修改,然后从这条边所在的点的线段树叶子开始向上 Update . 询问两

BZOJ 3779 重组病毒 LCT+线段树维护DFS序

题目大意:给定一棵树,初始每个点都有一个颜色,支持三种操作: 1.将某个点到根的路径上所有点染上一种新的颜色 2.将某个点到根的路径上所有点染上一种新的颜色,然后把根设为这个点 3.定义一个点的代价为这个点到根路径上颜色的种类数,求某个点子树中所有点代价的平均值 我真是炖了狗了-- 容易发现这玩应就是个LCT,操作1就是Access,操作2就是Move_To_Root,代价就是一个点到根路径上的虚边数量+1 我们用LCT模拟上述操作,用线段树维护DFS序维护信息,一旦LCT中出现了虚实边的切换,

BZOJ 2402 陶陶的难题II 二分答案+斜率优化+树链剖分+线段树维护凸包

题目大意:给定一棵树,每个点有两个坐标(x1,y1)和(x2,y2),多次询问某条链上选择两个点i和j(可以相同),求(y1i+y2j)/(x1i+x2j)的最大值 我竟没看出来这是01分数规划...真是老了... 二分答案ans,问题转化成验证(y1i+y2j)/(x1i+x2j)是否>=ans 将式子变形可得(y1i-ans*x1i)+(y2j-ans*x2j)>=0 加号两边独立,分别计算即可 问题转化为求链上y-ans*x最大的点 令P=y-ans*x 则y=ans*x+P 我们发现这

BZOJ 2124: 等差子序列 线段树维护hash

2124: 等差子序列 Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数.下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开. Output 对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”. Sample Input 2 3 1 3 2 3 3 2 1 Sample Output N Y HI

从《楼房重建》出发浅谈一类使用线段树维护前缀最大值的算法

首先需要申明的是,真的是浅谈,因为我对这个算法的认识还是非常低的. 既然是从<楼房重建>出发,那么当然是先看看这道题: [清华集训2013]楼房重建 bzoj 链接 题意简述: 有 \(n\) 栋楼,第 \(i\) 栋的高度为 \(H_i\),也就是说第 \(i\) 栋楼可以抽象成一条两端点为 \((i, 0)\) 和 \((i, H_i)\) 的线段. 初始时 \(H_i\) 均为 \(0\),要支持动态修改单点的 \(H_i\). 每次询问从 \(O(0, 0)\) 点可以看到多少栋楼房.