开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第25天,点击查看活动详情
[CQOI2006]简单题
题目描述
有一个 n 个元素的数组,每个元素初始均为 0。有 m 条指令,要么让其中一段连续序列数字反转——0 变 1,1 变 0(操作 1),要么询问某个元素的值(操作 2)。 例如当 n = 20 时,10 条指令如下:
输入格式
第一行包含两个整数 n, m,表示数组的长度和指令的条数; 以下 m 行,每行的第一个数 t 表示操作的种类:
若 t = 1,则接下来有两个数 L, R,表示区间 [L, R] 的每个数均反转; 若 t = 2,则接下来只有一个数 i,表示询问的下标。
输出格式
每个操作 2 输出一行(非 0 即 1),表示每次操作 2 的回答。
样例 #1
样例输入 #1
20 10
1 1 10
2 6
2 12
1 5 12
2 6
2 15
1 6 16
1 11 17
2 12
2 6
样例输出 #1
1
0
0
0
1
1
提示
对于 50% 的数据,1 ≤ n ≤ , 1 ≤ m ≤ ; 对于 100% 的数据,1 ≤ n ≤ , 1 ≤ m ≤ 5 × ,保证 L ≤ R。
分析
这是一道线段树的板子题,qaq,就是add函数+-操作。
代码
#include <iostream>
#define ll long long
#include <cmath>
using namespace std;
const int N=100010;
ll a[N],n,m;
struct tre{
ll l,r,sum,add,mul;
}tr[4*N];
inline void pushup(ll u){
tr[u].sum=tr[u+u].sum+tr[u+u+1].sum;
}
inline void build(ll u,ll l,ll r){
if(l==r){
tr[u]={l,r,a[l],0,1};
return;
}
tr[u]={l,r,0,0,1};
ll mid=l+r>>1;
build(u+u,l,mid);
build(u+u+1,mid+1,r);
pushup(u);
}
inline void opp(tre &tree,ll add,ll mul){
tree.sum=(tree.sum*mul+add*(tree.r-tree.l+1));
tree.mul=tree.mul*mul;
tree.add=(tree.add*mul+add);
}
inline void pushdown(ll u){
opp(tr[u+u],tr[u].add,tr[u].mul);
opp(tr[u+u+1],tr[u].add,tr[u].mul);
tr[u].mul=1,tr[u].add=0;
}
inline void modify(ll u,ll l,ll r,ll add,ll mul){
if(tr[u].l>=l && tr[u].r<=r){
opp(tr[u],add,mul);
return;
}
pushdown(u);
ll mid=tr[u].l+tr[u].r>>1;
if(r<=mid) modify(u+u,l,r,add,mul);
else{
if(l>mid) modify(u+u+1,l,r,add,mul);
else{
modify(u+u,l,mid,add,mul);
modify(u+u+1,mid+1,r,add,mul);
}
}
pushup(u);
}
ll query(ll u,ll l,ll r){
if(tr[u].l>=l && tr[u].r<=r){
return tr[u].sum;
}
pushdown(u);
ll mid=tr[u].l+tr[u].r>>1;
if(r<=mid) return query(u+u,l,r);
else{
if(l>mid) return query(u+u+1,l,r);
else return query(u+u,l,mid)+query(u+u+1,mid+1,r);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) a[i]=0;
build(1,1,n);
while(m--){
ll op,l,r;
cin>>op;
if(op==1){
cin>>l>>r;
modify(1,l,r,1,-1);
}
else{
cin>>l;
cout<<(query(1,l,l))<<"\n";
}
}
return 0;
}