CodeVS1690 开关灯 解题报告【数据结构】【线段树】
2017-08-27 20:06
453 查看
题目描述 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
解题报告
这道题的操作就区间取反+区间求和,用线段树实现。线段树的每一个点存储这段的和以及懒标记。其中懒标记的更新是nd->flag=!nd->flag(取反),而每一次求和应该是这段区间的长度减去原来的和(nd->sum=(rg-lf+1)-nd->sum)。
代码如下:
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
解题报告
这道题的操作就区间取反+区间求和,用线段树实现。线段树的每一个点存储这段的和以及懒标记。其中懒标记的更新是nd->flag=!nd->flag(取反),而每一次求和应该是这段区间的长度减去原来的和(nd->sum=(rg-lf+1)-nd->sum)。
代码如下:
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=100000; int n,m; int a[N+5]; struct node { int sum,flag; node *lson,*rson; void pushdown(int lf,int rg) { if(flag) { int mid=(lf+rg)>>1; lson->flag=!lson->flag; lson->sum=(mid-lf+1)-lson->sum; rson->flag=!rson->flag; rson->sum=(rg-mid)-rson->sum; flag=0; } } void update() { sum=lson->sum+rson->sum; } }; struct node dizhi[4*N+5],*tail=dizhi,*root; node *build(int lf,int rg) { node *nd=++tail; if(lf==rg) { nd->sum=0; nd->flag=0; } else { int mid=(lf+rg)>>1; nd->lson=build(lf,mid); nd->rson=build(mid+1,rg); nd->sum=nd->lson->sum+nd->rson->sum; nd->flag=0; } return nd; } void modify(node *nd,int lf,int rg,int L,int R) { if(L<=lf&&rg<=R) { nd->sum=(rg-lf+1)-nd->sum; nd->flag=!nd->flag; return ; } nd->pushdown(lf,rg); int mid=(lf+rg)>>1; if(L<=mid)modify(nd->lson,lf,mid,L,R); if(R>mid)modify(nd->rson,mid+1,rg,L,R); nd->update(); } int query(node *nd,int lf,int rg,int L,int R) { if(L<=lf&&rg<=R)return nd->sum; int mid=(lf+rg)>>1; nd->pushdown(lf,rg); long long rt=0; if(L<=mid)rt+=query(nd->lson,lf,mid,L,R); if(R>mid)rt+=query(nd->rson,mid+1,rg,L,R); nd->update(); return rt; } int main() { scanf("%d%d",&n,&m); root=build(1,n); while(m--) { int opt,lf,rg; scanf("%d%d%d",&opt,&lf,&rg); if(!opt)modify(root,1,n,lf,rg); else printf("%d\n",query(root,1,n,lf,rg)); } return 0; }
相关文章推荐
- codevs 1690 开关灯 线段树 解题报告
- CodeVS1369 xth 砍树 解题报告【数据结构】【线段树/树状数组】
- Codevs_1690_开关灯_(线段树)
- 【codevs1690】开关灯【线段树】
- 【codevs1690】开关灯,线段树练习
- codevs1690 开关灯(线段树)
- codevs 1690 开关灯 线段树
- Codevs 题目1690 开关灯(线段树区间异或)
- 【codevs1690】开关灯 线段树
- codevs 1690 开关灯 线段树水题
- 【codevs1690】开关灯 线段树 区间修改+区间求和(标记)
- 线段树--codevs 1690 开关灯
- [Miller-Rabin][CODEVS1702]素数判定2 解题报告
- 【解题报告】openjudge DNA排序 数据结构与算法mooc 内排序
- codevs 1282 约瑟夫问题 大暴力? 解题报告
- codevs 1219 骑士游历 DP 解题报告
- codevs 2622 数字序列 DP 解题报告
- 习题:codevs 1519 过路费 解题报告
- 【NOIP2000TG/codevs1017】 乘积最大 解题报告
- codevs 1231 最优布线问题 并查集 解题报告