原题:
农夫约翰试图让奶牛玩智力玩具来保持它们的敏锐。谷仓里的灯是较大的玩具之一。N(2≤N≤105) 个牛栏编号为 1…N,每个牛栏上面都有一盏灯。起初所有的灯都关着。
共有 M 次操作,分为两种。
指定一个区间 [Si,Ei],然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开);
指定一个区间 [Si,Ei],要求你输出这个区间内有多少盏灯是打开的。
一、整体思路
观察题目,涉及区间修改和区间查询,询问数量最多可以达到1e6,暴力查询会T,我们使用线段树,把每个询问的时间优化到logn,整个算法的时间复杂度就是O(mlogn),2s的时限是可以接受的。
二、实现细节
1.操作简化
我们可以把开灯的状态定义为1,反之为0.对于一个区间,偶数次修改相当于不变,我们可以使用异或(XOR)来快捷完成这个转换,代码像这样
l.tag ^= 1; r.tag ^= 1;
2.其他细节
这题线段树每个节点的初值都是0,可以不建树。
后面就是常规的区修和区查
AC代码
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
const int N = 100005;
struct note
{
int l,r,sum,tag;
}tree[N*4];
int ls(int p);
int rs(int p);
void buildTree(int p,int l,int r);
void pushup(int p);
void pushdown(int p);
void update(int p,int l,int r);
int query(int p,int l,int r);
int main()
{
IOS; int n,q; cin >> n >> q; buildTree(1,1,n);
for (int i = 1,op,l,r; i <= q; i++)
{
cin >> op >> l >> r;
if (l > r) swap(l,r);
if (op) cout << query(1,l,r) << "\n";
else update(1,l,r);
}
return 0;
}
int ls(int p)
{
return p << 1;
}
int rs(int p)
{
return p << 1 | 1;
}
void buildTree(int p,int l,int r)
{
tree[p] = {l,r,0,0};
if (l == r) return;
int mid = l + r >> 1;
buildTree(ls(p),l,mid);
buildTree(rs(p),mid+1,r);
pushup(p);
}
void pushup(int p)
{
tree[p].sum = tree[ls(p)].sum + tree[rs(p)].sum;
}
void pushdown(int p)
{
if (tree[p].tag)
{
tree[ls(p)].sum = (tree[ls(p)].r - tree[ls(p)].l + 1) - tree[ls(p)].sum;
tree[rs(p)].sum = (tree[rs(p)].r - tree[rs(p)].l + 1) - tree[rs(p)].sum;
tree[ls(p)].tag ^= 1; tree[rs(p)].tag ^= 1;
tree[p].tag ^= 1;
}
}
void update(int p,int l,int r)
{
if (l <= tree[p].l && tree[p].r <= r)
{
tree[p].tag ^= 1;
tree[p].sum = (tree[p].r - tree[p].l + 1) - tree[p].sum;
return;
}
pushdown(p);
int mid = tree[p].l + tree[p].r >> 1;
if (l <= mid) update(ls(p),l,r);
if (r > mid) update(rs(p),l,r);
pushup(p);
}
int query(int p,int l,int r)
{
if (l <= tree[p].l && tree[p].r <= r) return tree[p].sum;
pushdown(p);
int ans = 0;
int mid = tree[p].l + tree[p].r >> 1;
if (l <= mid) ans += query(ls(p),l,r);
if (r > mid) ans += query(rs(p),l,r);
return ans;
}
1015

被折叠的 条评论
为什么被折叠?



