bzoj 1858 线段树

思路:很明显的线段树,随便搞搞lazy标记,维护一下区间最长的1。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PII pair<int, int>
#define y1 skldjfskldjg
#define y2 skldfjsklejg
using namespace std;

const int N = 1e5 + 7;
const int M = 5e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;

int n, m, lazy[N << 2];
struct info {
    int m, l, r, s, w;
    info(){};
    info(int _m, int _l, int _r, int _s, int _w) {
        m = _m; w = _w;
        l = _l; r = _r;
        s = _s;
    }

    info operator + (const info &t) const {
        return info(max(max(m,t.m),r+t.l),l+(l==w)*t.l,t.r+(t.r==t.w)*r,s+t.s,w+t.w);
    }

    void change(int type) {
        if(!type) m = l = r = s = 0;
        else m = l = r = s = w;
    }
} a[N << 2], b[N << 2];

void pushdown(int rt, int l = 0, int r = 0) {
    if(!lazy[rt]) return;
    if(lazy[rt] == 1) {
        swap(a[rt << 1], b[rt << 1]);
        swap(a[rt << 1 | 1], b[rt << 1 | 1]);
        lazy[rt << 1] ^= 1;
        lazy[rt << 1 | 1] ^= 1;
    } else {
        int c = lazy[rt] - 2;
        a[rt << 1].change(c); b[rt << 1].change(c^1);
        a[rt << 1 | 1].change(c); b[rt << 1 | 1].change(c^1);
        lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt];
    }
    lazy[rt] = 0;
}

void build(int l, int r, int rt) {
    if(l == r) {
        a[rt].w = b[rt].w = 1;
        int x; scanf("%d", &x);
        a[rt].change(x);
        b[rt].change(x^1);
        return;
    }
    int mid = l + r >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    a[rt] = a[rt << 1] + a[rt << 1 | 1];
    b[rt] = b[rt << 1] + b[rt << 1 | 1];
}

void update(int L, int R, int c, int l, int r, int rt) {
    if(l >= L && r <= R) {
        if(c == 1) {
            swap(a[rt], b[rt]);
            lazy[rt] ^= 1;
        } else {
            a[rt].change(c-2);
            b[rt].change((c-2)^1);
            lazy[rt] = c;
        }
        return;
    }
    int mid = l + r >> 1;
    pushdown(rt, l, r);
    if(L <= mid) update(L, R, c, l, mid, rt << 1);
    if(R > mid) update(L, R, c, mid + 1, r, rt << 1 | 1);
    a[rt] = a[rt << 1] + a[rt << 1 | 1];
    b[rt] = b[rt << 1] + b[rt << 1 | 1];
}

info query(int L, int R, int l, int r, int rt) {
    if(l >= L && r <= R) return a[rt];
    int mid = l + r >> 1;
    pushdown(rt);
    if(R <= mid) return query(L, R, l, mid, rt << 1);
    if(L > mid) return query(L, R, mid + 1, r, rt << 1 | 1);
    return query(L, R, l, mid, rt << 1) + query(L, R, mid + 1, r, rt << 1 | 1);
}

int main() {
    scanf("%d%d", &n, &m);
    build(1, n, 1);
    while(m--) {
        int op, L, R;
        scanf("%d%d%d", &op, &L, &R);
        L++; R++;
        if(op == 0) {
            update(L, R, 2, 1, n, 1);
        } else if(op == 1) {
            update(L, R, 3, 1, n, 1);
        } else if(op == 2) {
            update(L, R, 1, 1, n, 1);
        } else if(op == 3) {
            printf("%d\n", query(L, R, 1, n, 1).s);
        } else {
            printf("%d\n", query(L, R, 1, n, 1).m);
        }
    }
    return 0;
}

/*
   10 10
   0 0 0 1 1 0 1 0 1 1
   1 0 2
   2 2 2
*/

原文地址:https://www.cnblogs.com/CJLHY/p/9589613.html

时间: 2024-10-10 05:20:05

bzoj 1858 线段树的相关文章

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 3681 线段树合并+网络流

思路: 暴力建图有n*m条边 考虑怎么优化 (那就只能加个线段树了呗) 然后我就不会写了..... 抄了一波题解 //By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=10050,M=N*100,inf=0x3f3f3f3f; vector<int>vec[N]; int n,m,first[M],next[M],v[M],w[M],tot,cnt=2,S=1,T=2; int lson[M

BZOJ 1012 线段树或单调队列

1012: [JSOI2008]最大数maxnumber 题意:两种操作:1.查询当前数列中末尾L个数中的最大的数:2.当前数列末尾插入一个数. tags:水题 线段树 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define FF(i,a,b) for (int i=a;i<=b;i++) #define F(i

BZOJ 4756 线段树合并(线段树)

思路: 1.最裸的线段树合并 2. 我们可以观察到子树求一个东西 那我们直接DFS序好了 入队的时候统计一下有多少比他大的 出的时候统计一下 减一下 搞定~ 线段树合并代码: //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=100050; int n,col[N],cpy[N],tree[N*100],lso

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

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

bzoj 3211 线段树

开方操作最多进行5次就可以把出现的任何数变成1. 所以用线段树暴力修改,以后修改时只需看一下是否当前区间都是0或1,如果是那么就直接返回. 1 /************************************************************** 2 Problem: 3211 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:1976 ms 7 Memory:7068 kb 8 **************

BZOJ 1012 线段树||单调队列

非常裸的线段树  || 单调队列: 假设一个节点在队列中既没有时间优势(早点入队)也没有值优势(值更大),那么显然不管在如何的情况下都不会被选为最大值. 既然它仅仅在末尾选.那么自然能够满足以上的条件. 线段树 #include "stdio.h" #include "string.h" struct node { int l,r,Max; }data[800010]; int Max(int a,int b) { if (a<b) return b; els

HYSBZ 1858 线段树 区间合并

1 //Accepted 14560 KB 1532 ms 2 //线段树 区间合并 3 /* 4 0 a b 把[a, b]区间内的所有数全变成0 5 1 a b 把[a, b]区间内的所有数全变成1 6 2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0 7 3 a b 询问[a, b]区间内总共有多少个1 8 4 a b 询问[a, b]区间内最多有多少个连续的1 9 */ 10 #include <cstdio> 11 #include <

bzoj 3999 线段树区间提取 有序链剖

看错题目了,想成每个城市都可以买一个东西,然后在后面的某个城市卖掉,问最大收益.这个可以类似维护上升序列的方法在O(nlog^3n)的时间复杂度内搞定 这道题用到的一些方法: 1. 可以将有关的线段提取出来,然后一起处理. 2. 线段树可以维护两个方向的信息,这样就可以处理树上有序的东西. 1 /************************************************************** 2 Problem: 3999 3 User: idy002 4 Langu