题目描述 Description
YYX家门前的街上有N(2<=N<=100000)盏路灯,在晚上六点之前,这些路灯全是关着的,六点之后,会有M(2<=m<=100000)个人陆续按下开关,这些开关可以改变从第i盏灯到第j盏灯的状态,现在YYX想知道,从第x盏灯到第y盏灯中有多少是亮着的(1<=i,j,x,y<=N)
输入描述 Input Description
第 1 行: 用空格隔开的两个整数N和M
第 2..M+1 行: 每行表示一个操作, 有三个用空格分开的整数: 指令号(0代表按下开关,1代表询问状态), x 和 y
输出描述 Output Description
第 1..询问总次数 行:对于每一次询问,输出询问的结果
样例输入 Sample Input
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4
样例输出 Sample Output
1
2
2
数据范围及提示 Data Size & Hint
一共4盏灯,5个操作,下面是每次操作的状态(X代表关上的,O代表开着的):
XXXX -> OOXX -> OXOO -> 询问1~3 -> OOXX -> 询问1~4
思路:
线段树模板(区间修改,区间查询)
一段区间的灯的状态为要么开着,要么关着。我们把关着的变成开的,整个状态就变成总灯数-当前状态的灯树。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 120000 using namespace std; int n,m,q,x,y,ans; int read() { ,f=; char ch=getchar(); ; ch=getchar();} +ch-'; ch=getchar();} return x*f; } struct Tree { int f,w,l,r; }tree[N*]; void build(int k,int l,int r) { tree[k].l=l,tree[k].r=r; if(tree[k].l==tree[k].r) return ; ; build(k<<,l,mid); build(k<<|,mid+,r); } void down(int k) { if(!tree[k].f) return ; tree[k<<].f=!tree[k<<].f; tree[k<<|].f=!tree[k<<|].f; tree[k<<].w=(tree[k<<].r-tree[k<<].l+)-tree[k<<].w; tree[k<<|].w=(tree[k<<|].r-tree[k<<|].l+)-tree[k<<|].w; tree[k].f=; } void change_interval(int k) { if(tree[k].l>=x&&tree[k].r<=y) { tree[k].w=(tree[k].r-tree[k].l+)-tree[k].w; tree[k].f=!tree[k].f; return ; } down(k); ; ); |); tree[k].w=tree[k<<].w+tree[k<<|].w; } void ask_interval(int k) { if(tree[k].l>=x&&tree[k].r<=y) { ans+=tree[k].w; return ; } down(k); ; ); |); } int main() { n=read(),m=read(); build(,,n); ;i<=m;i++) { q=read(),x=read(),y=read(); ans=; ) change_interval(); else { ask_interval(); printf("%d\n",ans); } } ; }