【codevs1690】开关灯【线段树】

题目描述 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 数据范围及提示 Data Size & Hint 一共4盏灯,5个操作,下面是每次操作的状态(X代表关上的,O代表开着的): XXXX -> OOXX -> OXOO -> 询问1~3 -> OOXX -> 询问1~4 题解: 区间取反和区间查询。灯亮用1表示,灯灭用0表示 线段树保存区间和。 一个区间取反后亮着灯的个数实际上是r-l+1-t[x]; 我们在下放标记时只需要lazy[x]=!lazy[x]。 代码:

#include<iostream>#include<cstdio>using namespace std;int t[1000001],n,m,kind,x,y,lazy[1000001];void paint(int k,int l,int r){t[k]=r-l+1-t[k];lazy[k]=!lazy[k];}void pushdown(int k,int l,int r){int mid;mid=(l+r)/2;paint(k*2,l,mid);paint(k*2+1,mid+1,r);lazy[k]=0;}void insert(int k,int l,int r,int ll,int rr){int mid;if (ll<=l&&r<=rr){paint(k,l,r);return;}mid=(l+r)/2;if (lazy[k]==1) pushdown(k,l,r);if (ll<=mid) insert(k*2,l,mid,ll,rr);if (mid<rr) insert(k*2+1,mid+1,r,ll,rr);t[k]=t[+1];}int qsum(int k,int l,int r,int ll,int rr){int mid,ans(0);if (ll<=l&&r<=rr) return t[k];mid=(l+r)/2;if (lazy[k]==1) pushdown(k,l,r);if (ll<=mid) ans+=qsum(k*2,l,mid,ll,rr);if (mid<rr) ans+=qsum(k*2+1,mid+1,r,ll,rr);return ans;}int main(){cin>>n>>m;for (int i=1;i<=m;i++){scanf(“,&kind,&x,&y);if (kind==0) insert(1,1,n,x,y);if (kind==1) printf(“%d\n”,qsum(1,1,n,x,y));}}

,一定要成为你工作最大的资产。

【codevs1690】开关灯【线段树】

相关文章:

你感兴趣的文章:

标签云: