现有 n 盏灯排成一排,从左到右依次编号为:1,2,……,n。然后依次执行 m 项操作。
操作分为两种:
灯在初始时都是关着的。
第一行有两个整数 n 和 m,分别表示灯的数目和操作的数目。
接下来有 m 行,每行有三个整数,依次为:c、a、b。其中 c 表示操作的种类。
a 和 b 则分别表示了操作区间的左右边界。
每当遇到第二种操作时,输出一行,包含一个整数,表示此时在查询的区间中打开的灯的数目。
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4
1
2
对于全部的测试点,保证 2≤n≤105,1≤m≤105,1≤a,b≤n,c∈{0,1}。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 3;
#define ll long long
ll a[maxn],w[maxn * 4],lzy[maxn * 4];
void pushup(const int u) {
w[u] = w[2 * u] + w[2 * u + 1];
}
bool InRange(int L,int R,int l,int r) {
return (l <= L) && (R <= r);
}//判断是否完全包含
bool OutoRange(int L,int R,int l,int r) {
return (R < l) || (L > r);
}//判断是否交集为空集
void maketag(int u,int len) {
lzy[u] ^= 1;
w[u] = len - w[u];
}//向下延迟修改
void pushdown(int u,int L,int R) {
int mid = (L + R) / 2;
maketag(2 * u,mid - L + 1);
maketag(2 * u + 1,R - mid);
lzy[u] = 0;
}//向下传递
ll query(int u,int L,int R,int l,int r) {
if (InRange(L,R,l,r))
return w[u];
else if(!OutoRange(L,R,l,r)) {
int mid = (L + R) / 2;
pushdown(u,L,R);
return query(2 * u,L,mid,l,r) +
query(2 * u + 1,mid + 1,R,l,r);
}
return 0;
}
void update(int u,int L,int R,int l,int r) {
if (InRange(L,R,l,r))
maketag(u,R - L + 1);
else if (!OutoRange(L,R,l,r)) {
int mid = (L + R) / 2;
pushdown(u,L,R);
update(2 * u,L,mid,l,r);
update(2 * u + 1,mid + 1,R,l,r);
pushup(u);
}
}
int main() {
int n,m;
cin >> n >> m;
memset(a,0,sizeof(a));
for (int i = 1; i <= m; i++) {
int op;
cin >> op;
if (op == 0) {
int l,r;
cin >> l >> r;
update(1,1,n,l,r);
}
if (op == 1) {
int l,r;
cin >> l >> r;
cout << query(1,1,n,l,r) << endl;
}
}
return 0;
}