首页 > 其他分享 >P2572 序列操作

P2572 序列操作

时间:2022-08-31 19:11:07浏览次数:77  
标签:pre suf val res sum tr 序列 操作 P2572

题目链接

  需要实现区间覆盖区间01取反区间求和以及区间查询最大连续段。区间覆盖很好实现,区间\(01\)取反只需要用分别统计\(01\)个数的时候将他俩交换就可以了,区间求和在取反之后只需要\(len - sum\)就可以求出来了。重点就是区间最大连续子段,分成三类:
    \(1.\)左区间全满且跨越到右区间
    \(2.\)右区间全满且跨越到左区间
    \(3.\)横跨左右区间但是都未满
  在标记上传的时候需要修改的信息比较多

	Info operator + (const Info& a, const Info& b) {
	    Info c;
	    c.siz = a.siz + b.siz;
	    c.sum = a.sum + b.sum;

	    for (int i = 0; i < 2; i++) {
	        c.pre[i] = a.pre[i];
	        if (i == 1 && a.sum == a.siz) {
	            c.pre[i] += b.pre[i];
	        } else if (i == 0 && a.sum == 0) {
	            c.pre[i] += b.pre[i];
	        }

	        c.suf[i] = b.suf[i];
	        if (i == 1 && b.sum == b.siz) {
	            c.suf[i] += a.suf[i];
	        } else if (i == 0 && b.sum == 0) {
	            c.suf[i] += a.suf[i];
	        }

	        c.val[i] = b.pre[i] + a.suf[i];
	        c.val[i] = std::max(c.val[i], a.val[i]);
	        c.val[i] = std::max(c.val[i], b.val[i]);
	        c.val[i] = std::max(std::max(c.val[i], c.pre[i]), c.suf[i]);
	    }

	    return c;
	}

  标记下传的时候注意先后顺序,应该是先执行区间覆盖操作,再执行区间反转操作,而且在区间覆盖操作完之后应该是要吧原有的区间翻转的标记清空的。

	void settag1(int u, int x) {
	    tr[u].res.sum = x * tr[u].res.siz;
	    tr[u].tag.tag1 = x;
	    tr[u].tag.tag2 = 0;
	    tr[u].res.val[x] = tr[u].res.pre[x] = tr[u].res.suf[x] = tr[u].res.siz;
	    tr[u].res.pre[x ^ 1] = tr[u].res.suf[x ^ 1] = tr[u].res.val[x ^ 1] = 0;
	}

	void settag2(int u) {
	    tr[u].res.sum = tr[u].res.siz - tr[u].res.sum;
	    if (~tr[u].tag.tag1) {
	        tr[u].tag.tag1 ^= 1;
	    } else {
	        tr[u].tag.tag2 ^= 1;
	    }

	    std::swap(tr[u].res.val[0], tr[u].res.val[1]);
	    std::swap(tr[u].res.pre[0], tr[u].res.pre[1]);
	    std::swap(tr[u].res.suf[0], tr[u].res.suf[1]);
	}

	void push(int u) {
	    if (~tr[u].tag.tag1) {
	        tr[u].tag.tag2 = 0;
	        settag1(u << 1, tr[u].tag.tag1);
	        settag1(u << 1 | 1, tr[u].tag.tag1);
	        tr[u].tag.tag1 = -1;
	    }
	    if (tr[u].tag.tag2) {
	        settag2(u << 1);
	        settag2(u << 1 | 1);
	        tr[u].tag.tag2 = 0;
	    }
	}

  剩下的就是中规中矩的线段树操作了

	#include <bits/stdc++.h>

	using i64 = long long;

	#define rep(i,a,n) for (int i = a; i < n; i ++ )
	#define per(i,a,n) for (int i = n; i >= a; i -- )
	#define all(v) v.begin(), v.end()
	#define SZ(s) int(s.size())
	#define pb push_back
	#define fi first
	#define se second
	//head

	const int N = 100010;

	int a[N];

	struct Info {
	    int siz, sum;
	    int pre[2], suf[2], val[2];
	};

	struct Tag {
	    int tag1, tag2;
	    Tag() : tag1(-1), tag2(0) {}
	};

	Info operator + (const Info& a, const Info& b) {
	    Info c;
	    c.siz = a.siz + b.siz;
	    c.sum = a.sum + b.sum;

	    for (int i = 0; i < 2; i++) {
	        c.pre[i] = a.pre[i];
	        if (i == 1 && a.sum == a.siz) {
	            c.pre[i] += b.pre[i];
	        } else if (i == 0 && a.sum == 0) {
	            c.pre[i] += b.pre[i];
	        }

	        c.suf[i] = b.suf[i];
	        if (i == 1 && b.sum == b.siz) {
	            c.suf[i] += a.suf[i];
	        } else if (i == 0 && b.sum == 0) {
	            c.suf[i] += a.suf[i];
	        }

	        c.val[i] = b.pre[i] + a.suf[i];
	        c.val[i] = std::max(c.val[i], a.val[i]);
	        c.val[i] = std::max(c.val[i], b.val[i]);
	        c.val[i] = std::max(std::max(c.val[i], c.pre[i]), c.suf[i]);
	    }

	    return c;
	}

	struct Node {
	    Info res;
	    Tag tag;
	} tr[N << 2];

	void build(int u, int l, int r) {
	    if (l == r) {
	        tr[u].res.pre[a[l]] = tr[u].res.suf[a[l]] = tr[u].res.val[a[l]] = tr[u].res.siz = 1;
	        tr[u].res.sum = a[l];
	        return ;
	    }
	    int mid = (l + r) >> 1;
	    build(u << 1, l, mid);
	    build(u << 1 | 1, mid + 1, r);
	    tr[u].res = tr[u << 1].res + tr[u << 1 | 1].res;
	}

	void settag1(int u, int x) {
	    tr[u].res.sum = x * tr[u].res.siz;
	    tr[u].tag.tag1 = x;
	    tr[u].tag.tag2 = 0;
	    tr[u].res.val[x] = tr[u].res.pre[x] = tr[u].res.suf[x] = tr[u].res.siz;
	    tr[u].res.pre[x ^ 1] = tr[u].res.suf[x ^ 1] = tr[u].res.val[x ^ 1] = 0;
	}

	void settag2(int u) {
	    tr[u].res.sum = tr[u].res.siz - tr[u].res.sum;
	    if (~tr[u].tag.tag1) {
	        tr[u].tag.tag1 ^= 1;
	    } else {
	        tr[u].tag.tag2 ^= 1;
	    }

	    std::swap(tr[u].res.val[0], tr[u].res.val[1]);
	    std::swap(tr[u].res.pre[0], tr[u].res.pre[1]);
	    std::swap(tr[u].res.suf[0], tr[u].res.suf[1]);
	}

	void push(int u) {
	    if (~tr[u].tag.tag1) {
	        tr[u].tag.tag2 = 0;
	        settag1(u << 1, tr[u].tag.tag1);
	        settag1(u << 1 | 1, tr[u].tag.tag1);
	        tr[u].tag.tag1 = -1;
	    }
	    if (tr[u].tag.tag2) {
	        settag2(u << 1);
	        settag2(u << 1 | 1);
	        tr[u].tag.tag2 = 0;
	    }
	}

	// assaign
	void change(int u, int l, int r, int ln, int rn, int x) {
	    push(u);
	    if (l >= ln && r <= rn) return void(settag1(u, x));
	    int mid = (l + r) >> 1;

	    if (mid >= ln) change(u << 1, l, mid, ln, rn, x);
	    if (mid < rn) change(u << 1 | 1, mid + 1, r, ln, rn, x);
	    tr[u].res = tr[u << 1].res + tr[u << 1 | 1].res;
	}

	void reverse(int u, int l, int r, int ln, int rn) {
	    push(u);
	    if (l >= ln && r <= rn) return void(settag2(u));
	    int mid = (l + r) >> 1;
	    if (mid >= ln) reverse(u << 1, l, mid, ln, rn);
	    if (mid < rn) reverse(u << 1 | 1, mid + 1, r, ln, rn);
	    tr[u].res = tr[u << 1].res + tr[u << 1 | 1].res;
	}

	Info query(int u, int l, int r, int ln, int rn) {
	    if (l >= ln && r <= rn) return tr[u].res;
	    int mid = (l + r) >> 1;
	    push(u);
	    if (mid >= rn) return query(u << 1, l, mid, ln, rn);
	    else if (mid < ln) return query(u << 1 | 1, mid + 1, r, ln, rn);
	    else return query(u << 1, l, mid, ln, rn) + query(u << 1 | 1, mid + 1, r, ln, rn);
	}

	signed main() {
	    std::cin.tie(nullptr)->sync_with_stdio(false);

	    int n, m;
	    std::cin >> n >> m;
	    for (int i = 1; i <= n; i++) 
	        std::cin >> a[i];

	    build(1, 1, n);

	    for (int i = 1; i <= m; i ++) {
	        int op, l, r;
	        std::cin >> op >> l >> r;
	        l++, r++;
	        if (op <= 1) {
	            change(1, 1, n, l, r, op);
	        } else if (op == 2) {
	            reverse(1, 1, n, l, r);
	        } else if (op == 3) {
	            std::cout << query(1, 1, n, l, r).sum << "\n";
	        } else {
	            std::cout << query(1, 1, n, l, r).val[1] << "\n";
	        }
	    }

	    return 0 ^ 0;
	}

标签:pre,suf,val,res,sum,tr,序列,操作,P2572
From: https://www.cnblogs.com/Haven-/p/16644247.html

相关文章

  • 物联网低代码平台如何使用操作日志?
    AIRIOT物联网低代码平台具有系统维护功能,包括操作日志和服务管理两部分。操作日志记录了用户所有的操作行为,如系统每次登录或系统模型被更改,均会产生一个系统操作日志,系统......
  • gpio的porbe操作
    dts描述gpio1:gpio@0209c000{ compatible="fsl,imx6ul-gpio","fsl,imx35-gpio"; reg=<0x0209c0000x4000>; interrupts=<GIC_SPI66IRQ_TYPE_LEVEL_HIGH>, ......
  • 操作系统实战45讲- 02 几行汇编几行C:实现一个最简单的内核
    本节源代码位置https://gitee.com/lmos/cosmos/tree/master/lesson02/HelloOSHelloOS之前,我们先要搞清楚HelloOS的引导流程,如下图所示:PC机BIOS固件是固化在PC......
  • 《穿越时空的git》之创建版本库和常用命令操作
    ⬇️点击“下方链接”,提升测试核心竞争力!>>更多技术文章分享和免费资料领取Git是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。Git......
  • 模型类序列化器的声明和操作使用
    ModelSerializer与常规的Serializer相同,但额外提供了:·基于模型类自动生成一系列字段·基于模型类自动为Serializer生成validators,比如unique_together·包含默认的cre......
  • Orcle 命令面板的操作
    SQL>showuser;显示当前登录用户SQL>clearscreen;清空屏幕SQL>hostcls;清空屏幕SQL>spool(保存的路径假设为A)将以下执行的sql语句和执行结果......
  • Liunx 磁盘挂载操作
    磁盘挂载指南一、判断根目录类型1、进入系统之后,执行命令:lsblk ,查看现有系统的磁盘挂载情况                       ......
  • 动态规划之——最长递增子序列
    最长递增子序列(LongestIncreasingSubsequence)是指在给定的一组数字中,按照从左向右顺序,由递增的数字组成的子序列(中间可以有间隔)中,取长度最大的子序列即为最长递增子序列......
  • 序列化器:反序列换-添加和更新数据操作
    前端传到后端需要反序列化,后端传到前端需要序列化正常需要serializer两次:fromdjango.viewsimportViewfrom.modelsimportStudentfrom.serializersimportStude......
  • PHP文件操作
    //php读文件$data=file_get_contents('./1.txt');var_dump($data);//php写文件file_put_contents('./1.txt',date('Y-m-dH:i:s').PHP_EOL,FILE_APPEND);/**......