zoukankan      html  css  js  c++  java
  • [Luogu] P2572 [SCOI2010]序列操作

    (Link)

    Description

    lxhgww最近收到了一个(01)序列,序列里面包含了(n)个数,下标从(0)开始。这些数要么是(0),要么是(1),现在对于这个序列有五种变换操作和询问操作:

    • 0 l r([l,r])区间内的所有数全变成(0)
    • 1 l r([l,r])区间内的所有数全变成(1)
    • 2 l r([l,r])区间内的所有数全部取反,也就是说把所有的(0)变成(1),把所有的(1)变成(0)
    • 3 l r 询问([l,r])区间内总共有多少个(1)
    • 4 l r 询问([l,r])区间内最多有多少个连续的(1)

    对于每一种询问操作,lxhgww 都需要给出回答,聪明的程序员们,你们能帮助他吗?

    Solution

    复杂的线段树。

    考虑分别维护(1)的个数和,赋值标记,翻转标记,(1)(0)的最长连续、最长前缀和后缀。注意顺序,分别维护即可。

    这些其实开始都考虑到了,但就是翻转标记出了问题,调了我好久。之前我是写的如果有(2)操作,就标记翻转为(1),然后(pushdown)到子区间翻转标记都为(1),但这样是错的。因为某个标记放在那里,可能还没有下传。这时再来(pushdown)一个翻转标记,不就等于没有翻转吗?而对于我之前的想法,一个区间无论被不断翻转了多少次,都会被打上标记,就错了。所以标记应该是(0sim{1},1sim{0})

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ls(x) (x << 1)
    #define rs(x) (x << 1 | 1)
    
    int n, m, a[100005];
    
    struct node
    {
    	int l, r, sum, tag, rev, mx1, suf1, pre1, mx2, suf2, pre2;
    }t[400005];
    
    int read()
    {
    	int x = 0, fl = 1; char ch = getchar();
    	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
    	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
    	return x * fl;
    }
    
    void push_up(int p)
    {
    	t[p].sum = t[ls(p)].sum + t[rs(p)].sum;
    	t[p].mx1 = max(max(t[ls(p)].mx1, t[rs(p)].mx1), t[ls(p)].suf1 + t[rs(p)].pre1);
    	t[p].pre1 = t[ls(p)].pre1 + (t[ls(p)].pre1 == t[ls(p)].r - t[ls(p)].l + 1) * t[rs(p)].pre1;
    	t[p].suf1 = t[rs(p)].suf1 + (t[rs(p)].suf1 == t[rs(p)].r - t[rs(p)].l + 1) * t[ls(p)].suf1;
    	t[p].mx2 = max(max(t[ls(p)].mx2, t[rs(p)].mx2), t[ls(p)].suf2 + t[rs(p)].pre2);
    	t[p].pre2 = t[ls(p)].pre2 + (t[ls(p)].pre2 == t[ls(p)].r - t[ls(p)].l + 1) * t[rs(p)].pre2;
    	t[p].suf2 = t[rs(p)].suf2 + (t[rs(p)].suf2 == t[rs(p)].r - t[rs(p)].l + 1) * t[ls(p)].suf2;
    	return;
    }
    
    void push_down(int p)
    {
    	if (t[p].tag != -1)
    	{
    		t[ls(p)].tag = t[rs(p)].tag = t[p].tag;
    		t[ls(p)].rev = t[rs(p)].rev = 0;
    		t[ls(p)].sum = (t[ls(p)].r - t[ls(p)].l + 1) * t[p].tag;
    		t[rs(p)].sum = (t[rs(p)].r - t[rs(p)].l + 1) * t[p].tag;
    		t[ls(p)].mx1 = (t[ls(p)].r - t[ls(p)].l + 1) * t[p].tag;
    		t[rs(p)].mx1 = (t[rs(p)].r - t[rs(p)].l + 1) * t[p].tag;
    		t[ls(p)].pre1 = (t[ls(p)].r - t[ls(p)].l + 1) * t[p].tag;
    		t[rs(p)].pre1 = (t[rs(p)].r - t[rs(p)].l + 1) * t[p].tag;
    		t[ls(p)].suf1 = (t[ls(p)].r - t[ls(p)].l + 1) * t[p].tag;
    		t[rs(p)].suf1 = (t[rs(p)].r - t[rs(p)].l + 1) * t[p].tag;
    		t[ls(p)].mx2 = (t[ls(p)].r - t[ls(p)].l + 1) * (!t[p].tag);
    		t[rs(p)].mx2 = (t[rs(p)].r - t[rs(p)].l + 1) * (!t[p].tag);
    		t[ls(p)].pre2 = (t[ls(p)].r - t[ls(p)].l + 1) * (!t[p].tag);
    		t[rs(p)].pre2 = (t[rs(p)].r - t[rs(p)].l + 1) * (!t[p].tag);
    		t[ls(p)].suf2 = (t[ls(p)].r - t[ls(p)].l + 1) * (!t[p].tag);
    		t[rs(p)].suf2 = (t[rs(p)].r - t[rs(p)].l + 1) * (!t[p].tag);
    		t[p].tag = -1;
    	}
    	if (t[p].rev)
    	{
    		t[ls(p)].rev = 1 - t[ls(p)].rev;
    		t[rs(p)].rev = 1 - t[rs(p)].rev;
    		t[ls(p)].sum = t[ls(p)].r - t[ls(p)].l + 1 - t[ls(p)].sum;
    		t[rs(p)].sum = t[rs(p)].r - t[rs(p)].l + 1 - t[rs(p)].sum;
    		swap(t[ls(p)].mx1, t[ls(p)].mx2); swap(t[ls(p)].pre1, t[ls(p)].pre2); swap(t[ls(p)].suf1, t[ls(p)].suf2);
    		swap(t[rs(p)].mx1, t[rs(p)].mx2); swap(t[rs(p)].pre1, t[rs(p)].pre2); swap(t[rs(p)].suf1, t[rs(p)].suf2);
    		t[p].rev = 0;
    	}
    	return;
    }
    
    void build(int p, int l0, int r0)
    {
    	t[p].l = l0; t[p].r = r0; t[p].tag = -1;
    	if (l0 == r0)
    	{
    		t[p].sum = a[l0];
    		t[p].pre1 = t[p].suf1 = t[p].mx1 = a[l0];
    		t[p].pre2 = t[p].suf2 = t[p].mx2 = (!a[l0]);
    		return;
    	}
    	int mid = (t[p].l + t[p].r) >> 1;
    	build(ls(p), l0, mid);
    	build(rs(p), mid + 1, r0);
    	push_up(p);
    	return;
    }
    
    void update(int p, int l0, int r0, int tp)
    {
    	if (l0 <= t[p].l && t[p].r <= r0)
    	{
    		if (tp == 1)
    		{
    			t[p].sum = 0; t[p].tag = 0; t[p].rev = 0;
    			t[p].mx1 = t[p].suf1 = t[p].pre1 = 0;
    			t[p].mx2 = t[p].suf2 = t[p].pre2 = t[p].r - t[p].l + 1;
    		}
    		else if (tp == 2)
    		{
    			t[p].sum = t[p].r - t[p].l + 1; t[p].tag = 1; t[p].rev = 0;
    			t[p].mx1 = t[p].suf1 = t[p].pre1 =  t[p].r - t[p].l + 1;
    			t[p].mx2 = t[p].suf2 = t[p].pre2 = 0;
    		}
    		else
    		{
    			t[p].sum = (t[p].r - t[p].l + 1) - t[p].sum; t[p].rev = 1 - t[p].rev;
    			swap(t[p].mx1, t[p].mx2); swap(t[p].pre1, t[p].pre2); swap(t[p].suf1, t[p].suf2);
    		}
    		return;
    	}
    	push_down(p);
    	int mid = (t[p].l + t[p].r) >> 1;
    	if (l0 <= mid) update(ls(p), l0, r0, tp);
    	if (r0 > mid) update(rs(p), l0, r0, tp);
    	push_up(p);
    	return;
    }
    
    int query1(int p, int l0, int r0)
    {
    	if (l0 <= t[p].l && t[p].r <= r0) return t[p].mx1;
    	push_down(p);
    	int mid = (t[p].l + t[p].r) >> 1, now = 0, tt = 0;
    	if (l0 <= mid) tt ++ , now = max(now, query1(ls(p), l0, r0));
    	if (r0 > mid) tt ++ , now = max(now, query1(rs(p), l0, r0));
    	if (tt == 2) now = max(now, min(t[ls(p)].suf1, t[ls(p)].r - l0 + 1) + min(t[rs(p)].pre1, r0 - t[rs(p)].l + 1));
    	return now;
    }
    
    int query2(int p, int l0, int r0)
    {
    	if (l0 <= t[p].l && t[p].r <= r0) return t[p].sum;
    	push_down(p);
    	int mid = (t[p].l + t[p].r) >> 1, s = 0;
    	if (l0 <= mid) s = s + query2(ls(p), l0, r0);
    	if (r0 > mid) s = s + query2(rs(p), l0, r0);
    	return s;
    }
    
    int main()
    {
    	int n = read(), m = read();
    	for (int i = 1; i <= n; i ++ )
    		a[i] = read();
    	build(1, 1, n);
    	while (m -- )
    	{
    		int opt = read();
    		if (opt == 0)
    		{
    			int l0 = read() + 1, r0 = read() + 1;
    			update(1, l0, r0, 1);
    		}
    		else if (opt == 1)
    		{
    			int l0 = read() + 1, r0 = read() + 1;
    			update(1, l0, r0, 2);
    		}
    		else if (opt == 2)
    		{
    			int l0 = read() + 1, r0 = read() + 1;
    			update(1, l0, r0, 3);
    		}
    		else if (opt == 3)
    		{
    			int l0 = read() + 1, r0 = read() + 1;
    			printf("%d
    ", query2(1, l0, r0));
    		}
    		else
    		{
    			int l0 = read() + 1, r0 = read() + 1;
    			printf("%d
    ", query1(1, l0, r0));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    基础学习总结(四)---内存获取、XML之PULL解析
    基础学习总结(三)--文本、SD卡数据读写
    基础学习总结(二)---认识布局与配置测试环境
    基础学习总结(一)--工程结构与打包过程
    StreamReader和StreamWrite与FileStream区别
    redis笔记
    linux 下文件显示行数
    php判断页面访问是移动端还是pc端
    redis
    判断链接是否为图片
  • 原文地址:https://www.cnblogs.com/andysj/p/14008065.html
Copyright © 2011-2022 走看看