題目大意
進行兩項區間操作,一種是修改區間和,一種是查詢區間和,資料範圍不大,顯然,可以以線段樹解,其中,修改區間和比較簡單,用區間總長度減去區間和即可,即\(tree[root].value =(tree[root].r - tree[root].l + 1) - tree[root].value\),區間查詢就是普通的線段樹區間查詢。複雜度分析,修改查詢皆為\(O(logn)\)
程式碼如下
#include <iostream>
#include <cstdio>
using namespace std;
int n, m;
const int maxn = 1e5 + 5;
struct segment_tree
{
int l, r;
int value;
int lazy_tag;
};
segment_tree tree[maxn * 4];
void pushup(int root)
{
tree[root].value = tree[root << 1].value + tree[(root << 1) + 1].value;
}
void build(int root, int l, int r)
{
tree[root].l = l, tree[root].r = r;
if(l == r)
{
tree[root].value = 0;
return;
}
int mid = (l + r) >> 1;
build(root << 1, l, mid);
build((root << 1) + 1, mid + 1, r);
pushup(root);
}
void pushdown(int root)
{
if(tree[root].lazy_tag == 0) return;
tree[root << 1].lazy_tag ^= 1, tree[(root << 1) + 1].lazy_tag ^= 1;
tree[root << 1].value = (tree[root << 1].r - tree[root << 1].l + 1) - tree[root << 1].value;
tree[(root << 1) + 1].value = tree[(root << 1) + 1].r - tree[(root << 1) + 1].l + 1 -tree[(root << 1) + 1].value;
tree[root].lazy_tag = 0;
}
void update(int root, int L, int R)
{
int l = tree[root].l, r = tree[root].r;
if(L <= l && r <= R)
{
tree[root].lazy_tag ^= 1;
tree[root].value = (r - l + 1) - tree[root].value;
return;
}
int mid = (l + r) >> 1;
tree[root].lazy_tag %= 2;
pushdown(root);
if(L <= mid) update(root << 1, L, R);
if(R > mid)update((root << 1) + 1, L, R);
pushup(root);
}
int query(int root, int L, int R)
{
int l = tree[root].l, r = tree[root].r;
if(L <= l && r <= R) return tree[root].value;
int res = 0;
int mid = (l + r) >> 1;
tree[root].lazy_tag %= 2;
pushdown(root);
if(L <= mid) res += query(root << 1, L, R);
if(R > mid) res += query((root << 1) + 1, L, R);
return res;
}
int main()
{
scanf("%d%d", &n, &m);
build(1, 1, n);
while(m--)
{
int opt;
scanf("%d", &opt);
if(opt == 0)
{
int a, b;
scanf("%d%d", &a, &b);
update(1, a, b);
}
else
{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", query(1, a, b));
}
}
return 0;
}