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

思路:

我们可以搞一棵线段树

对于一段区间有6种情况需要讨论

左上右下、左上右上、左下右下、左下右上

这四种比较好维护

用左上右下举个例子吧

就是左儿子的左上右下&左区间到右区间下面有路&右儿子的左下右下

或者是左儿子的左上右上&左区间到右区间上面有路&右儿子的左上右下

还有两种  区间的左(右)端点上下能不能联通 需要维护

这种就是左儿子的上下连通或(左上右上&左上右下&左到右两条路都联通&右儿子的上下联通)

(假设c1<c2)

最后要查的是 1->c1 (可以1~c1上下联通再c1[!r1]->c2)

c1->c2(直接联通当然最好)

c2->cn

还有一种是1~c1上下联通&c2~n上下联通&c1[!r1]与c2[!r2]上下联通

4种分类讨论即可

//By SiriusRen
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=100050;
int map[N][2],map2[N],n,r1,c1,r2,c2,jy;
char op[15];
struct Node{bool b[2][2],c[2];}tree[N*16];
Node push_up(Node L,Node R,int mid){
    Node tmp;
    tmp.b[0][0]=(L.b[0][0]&map[mid][0]&R.b[0][0])|(L.b[0][1]&map[mid][1]&R.b[1][0]);
    tmp.b[0][1]=(L.b[0][0]&map[mid][0]&R.b[0][1])|(L.b[0][1]&map[mid][1]&R.b[1][1]);
    tmp.b[1][0]=(L.b[1][0]&map[mid][0]&R.b[0][0])|(L.b[1][1]&map[mid][1]&R.b[1][0]);
    tmp.b[1][1]=(L.b[1][0]&map[mid][0]&R.b[0][1])|(L.b[1][1]&map[mid][1]&R.b[1][1]);
    tmp.c[0]=L.c[0]|(L.b[0][0]&map[mid][0]&map[mid][1]&L.b[1][1]&R.c[0]);
    tmp.c[1]=R.c[1]|(R.b[0][0]&map[mid][0]&map[mid][1]&R.b[1][1]&L.c[1]);
    return tmp;
}
void build(int l,int r,int pos){
    if(l==r){tree[pos].b[1][1]=tree[pos].b[0][0]=1;return;}
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    build(l,mid,lson),build(mid+1,r,rson);
}
void insert(int l,int r,int pos,int L,int num,bool v){
    if(l==r){
        if(num==2)tree[pos].b[0][1]=tree[pos].b[1][0]=tree[pos].c[0]=tree[pos].c[1]=map2[l]=v;
        else map[l][num]=v;return;
    }
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<L)insert(mid+1,r,rson,L,num,v);
    else insert(l,mid,lson,L,num,v);
    tree[pos]=push_up(tree[lson],tree[rson],mid);
}
Node query(int l,int r,int pos,int L,int R){
    if(l>=L&&r<=R)return tree[pos];
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<L)return query(mid+1,r,rson,L,R);
    else if(mid>=R)return query(l,mid,lson,L,R);
    else return push_up(query(l,mid,lson,L,R),query(mid+1,r,rson,L,R),mid);
}
int main(){
    scanf("%d",&n),build(1,n,1);
    while(scanf("%s",op)&&op[0]!=‘E‘){
        scanf("%d%d%d%d",&r1,&c1,&r2,&c2),r1--,r2--;
        if(c1>c2)swap(c1,c2),swap(r1,r2);
        if(op[0]==‘A‘){
            Node a=query(1,n,1,1,c1),b=query(1,n,1,c2,n),c=query(1,n,1,c1,c2);
            if(c.b[r1][r2]|(a.c[1]&c.b[!r1][r2])|(b.c[0]&c.b[r1][!r2])|(b.c[0]&a.c[1]&c.b[!r1][!r2]))puts("Y");
            else puts("N");
        }
        else{
            if(r1==r2)jy=(r1==1);
            else jy=2;
            insert(1,n,1,c1,jy,op[0]==‘O‘);
        }
    }
}
时间: 2024-10-05 22:31:17

BZOJ 1018 线段树维护图的连通性问题的相关文章

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 1018 线段树维护连通性

本题将一道LCT的题特殊化(支持加边和删边,询问图的连通性),将图变成了2×m的网格图,然后就神奇地可以用线段树来维护. 对于每个区间[l,r],维护其四个角落之间的连通性(仅仅通过[l,r]这段的边构建起的连通性). 查询[l,r]时,先计算出[1,l-1],[l,r],[r+1,c]这三个线段的连通性,然后将[l,r]的四个角变成并查集的4个点,先用[l,r]中的6种关系更新,在看是否可以从左上角的点通过左边区间绕道左下角,以及从右上角通过右边区间绕道右下角,该并的并起来后直接看查询的点是否

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

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

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

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

[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

HDU 5068 Harry And Math Teacher( 矩阵乘法 + 线段树维护 )

HDU 5068 Harry And Math Teacher( 矩阵乘法 + 线段树维护 ) 题意: 首先是这题题意理解错误,,其次是这题无法理解状态... 已经不是英文有多烂的情况了,是中文没学好啊.....大学不学语文才是真正的硬伤啊 题目意思 有一个城堡有很多层楼, 每层楼有2个门,每个门里面又有两个楼梯,可以通往上一层的两个门 问,从x层楼到y层楼有多少中方法(不能返回) 具体看图吧,,,已经不会说话了 1 #include <cstdio> 2 #include <cstri