区间修改和区间查询的话,想到线段树,每次区间的内的操作就用区间长度减去已经亮了的灯的数量。然后将懒标记反转即可。
点击查看代码
#include <iostream>
#include <stack>
#include <cmath>
#include <algorithm>
#include <set>
#include <vector>
#include <climits>
#include <string.h>
#include <map>
#include <queue>
#include <list>
#include <cmath>
#include <iomanip>
#define int long long
#define ios ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define lc u<<1
#define rc u<<1|1
#define gcd __gcd
#define double long double
#define endl "\n"
#define INF LLONG_MAX
#define mod 1000000007
#define N 1000005
const double PI = 3.14159265358979323846;
using namespace std;
int n, m, w[1000005];
struct Tree { int l, r, sum, add; }tr[4 * 1000005];//sum区间内开灯的数量
void pushup(int u) { tr[u].sum = tr[lc].sum + tr[rc].sum; }//上传
void pushdown(int u)//下传
{
if (tr[u].add)
{
tr[lc].sum = (tr[lc].r - tr[lc].l + 1 - tr[lc].sum);
tr[rc].sum = (tr[rc].r - tr[rc].l + 1 - tr[rc].sum);
tr[lc].add ^= 1;tr[rc].add ^= 1;
tr[u].add = 0;
}
}
void build(int u, int l, int r)
{
tr[u] = { l,r,0,0 };
if (l == r)return;//到根节点了
int m = l + r >> 1;
build(lc, l, m); build(rc, m + 1, r);
}
void change(int u, int l, int r)//区间修改
{
if (l <= tr[u].l && r >= tr[u].r)//覆盖所以做懒标记
{
tr[u].sum = tr[u].r - tr[u].l + 1 - tr[u].sum;
tr[u].add ^= 1;
return;
}
int m = tr[u].l + tr[u].r >> 1;
pushdown(u);//去除懒标记
if (l <= m)change(lc, l, r);
if (r > m)change(rc, l, r);
pushup(u);//跟新节点
}
int query(int u, int l, int r)//查询
{
if (l <= tr[u].l && tr[u].r <= r)return tr[u].sum;//覆盖返回
int m = tr[u].l + tr[u].r >> 1;
pushdown(u);
int sum = 0;
if (l <= m)sum += query(lc, l, r);//覆盖返回,所以全部传过去
if (r > m)sum += query(rc, l, r);
return sum;
}
signed main()
{
ios;//会超时
cin >> n >> m;
build(1, 1, n);//建树
while (m--)
{
int op, a, b; cin >> op >> a >> b;
if (op == 0)change(1, a, b);
else cout << query(1, a, b) << endl;
}
}