洛谷题单指南-线段树-P3870 [TJOI2009] 开关

原题链接:https://www.luogu.com.cn/problem/P3870

题意解读:有n个数的序列,初始都是0,支持两种操作:将区间[l,r]内所有数异或1,求区间[l,r]内1个个数,输出所有求区间1的个数操作的结果。

解题思路:

灯的开关可以用0,1表示,改变灯的状态可以用异或操作,统计多少灯是开的就是计算1的个数,因此该题很容易进行转化。

现在要分析两个关键点:

1、计算区间1的个数是否具有可合并性?

显然,对于mid=(l+r)/2,区间[l,r]中1的个数 = [l,mid]中1的个数 + [mid+1,r]中1的个数,具有可合并行。

2、元素进行异或1是否具有可加性?

对一个开关tag,按一下异或1,状态是tag ^= 1,再按一下再异或1,状态同样tag ^= 1,具有可加性。

因此,此题可以用线段树解决,区间1的个数可以作为树节点的信息,当前开关的状态可以作为树节点的懒标记。

当更新节点并添加懒标记时:

void addtag(int u, int stat)
{
    //对区间所有数异或1,则区间1的个数变成区间0的个数
    tr[u].sum = (tr[u].r - tr[u].l + 1) - tr[u].sum;
    //懒标记异或上1
    tr[u].stat ^= stat;
}

100分代码:

 

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;

struct Node
{
    int l, r;
    int sum; //区间[l,r]中1的个数
    int stat; //懒标记,表示所有子节点的值都要异或stat
} tr[N * 4];
int n, m;

void pushup(int u)
{
    tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}

void build(int u, int l, int r)
{
    tr[u] = {l, r};
    if(l == r) tr[u].sum = 0, tr[u].stat = 0;
    else 
    {
        int mid = l + r >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}

void addtag(int u, int stat)
{
    tr[u].sum = tr[u].r - tr[u].l + 1 - tr[u].sum;
    tr[u].stat ^= stat;
}

void pushdown(int u)
{
    if(tr[u].stat)
    {
        addtag(u << 1, tr[u].stat);
        addtag(u << 1 | 1, tr[u].stat);
        tr[u].stat = 0;
    }
}

int query(int u, int l, int r)
{
    if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
    else if(tr[u].l > r || tr[u].r < l) return 0;
    else
    {
        pushdown(u);
        return query(u << 1, l, r) + query(u << 1 | 1, l, r);
    }
}

void update(int u, int l, int r)
{
    if(tr[u].l >= l && tr[u].r <= r) addtag(u, 1);
    else if(tr[u].l > r || tr[u].r < l) return;
    else
    {
        pushdown(u);
        update(u << 1, l, r);
        update(u << 1 | 1, l, r);
        pushup(u);
    }
}

int main()
{
    cin >> n >> m;
    build(1, 1, n);
    int op, x, y;
    while(m--)
    {
        cin >> op >> x >> y;
        if(op == 0) update(1, x, y);
        else cout << query(1, x, y) << endl;
    }
}

 

posted @ 2024-11-27 16:17  五月江城  阅读(6)  评论(0编辑  收藏  举报