题目描述
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() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } struct Tree { int f,w,l,r; }tree[N*4]; void build(int k,int l,int r) { tree[k].l=l,tree[k].r=r; if(tree[k].l==tree[k].r) return ; int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void down(int k) { if(!tree[k].f) return ; tree[k<<1].f=!tree[k<<1].f; tree[k<<1|1].f=!tree[k<<1|1].f; tree[k<<1].w=(tree[k<<1].r-tree[k<<1].l+1)-tree[k<<1].w; tree[k<<1|1].w=(tree[k<<1|1].r-tree[k<<1|1].l+1)-tree[k<<1|1].w; tree[k].f=0; } void change_interval(int k) { if(tree[k].l>=x&&tree[k].r<=y) { tree[k].w=(tree[k].r-tree[k].l+1)-tree[k].w; tree[k].f=!tree[k].f; return ; } down(k); int mid=(tree[k].l+tree[k].r)>>1; if(x<=mid) change_interval(k<<1); if(y>mid) change_interval(k<<1|1); tree[k].w=tree[k<<1].w+tree[k<<1|1].w; } void ask_interval(int k) { if(tree[k].l>=x&&tree[k].r<=y) { ans+=tree[k].w; return ; } down(k); int mid=(tree[k].l+tree[k].r)>>1; if(x<=mid) ask_interval(k<<1); if(y>mid) ask_interval(k<<1|1); } int main() { n=read(),m=read(); build(1,1,n); for(int i=1;i<=m;i++) { q=read(),x=read(),y=read(); ans=0; if(q==0) change_interval(1); else { ask_interval(1); printf("%d\n",ans); } } return 0; }