G. 小 W 开关灯 [ Problem 4467 ] [ Discussion ]
Description
晚上到家小 W 通过开关灯来保持自己神经的兴奋以便清醒地理笔记。N(2≤N≤100,000)盏灯被连续的编号为 1…N。刚回到家的时候,所有的灯都是关闭的。
小W 通过 N个按钮来控制灯的开关, 按第 i 个按钮可以改变第 i 盏灯的状态。
小W 发出 M (1≤M≤100,000)条指令,每个指令都是两个整数中的一个(0 或 1)。
第1 种指令(用 0 表示)包含两个数字 SiSi 和 Ei(1≤Si≤Ei≤N),它们表示起始开关和终止开关。小 W 需要把从 Si 到 Ei之间的按钮都按一次,就可以完成这个指令。
第2 种指令(用 1 表示)同样包含两个数字 Si 和 Ei(1≤Si≤Ei≤N),不过这种指令是询问从 Si 到 Ei 之间的灯有多少是亮着的。
请你帮助小 W 得到正确的答案。
Input
第1 行: 用空格隔开的两个整数 N 和 M。
第2..M+1 行: 每行表示一个操作, 有三个用空格分开的整数: 指令号, Si 和 Ei。
Output
对于每一次询问, 输出一行表示询问的结果。
Samples
Hint
【样例解释】
一共有 4 盏灯, 5 个指令。 下面是执行的情况:
1 2 3 4
Init: O O O O O = 关 * = 开
0 1 2 -> * * O O 改变灯 1 和 2 的状态
0 2 4 -> * O * *
1 2 3 -> 1 输出在 2..3 的范围内有多少灯是亮的
0 2 4 -> * * O O 改变灯 2 ,3 和 4 的状态
1 1 4 -> 2 输出在 1..4 的范围内有多少灯是亮的
【数据规模】
- 对于 20% 的数据: 1≤N,M≤100。
- 对于 40% 的数据: 1≤N,M≤10000。
- 对于另外 30% 的数据: 只有最后一组是 1 指令,前 M-1 组为 0 指令。
- 对于 100% 的数据: 1≤N,M≤100000。
Source
石光中学 2018泉州集训提高组day4#pragma GCC optimize(1) #pragma GCC optimize(2) #pragma GCC optimize(3,"Ofast","inline") #include<bits/stdc++.h> using namespace std; typedef long long ll; template <typename Tp> void read(Tp &x){ x=0;char ch=1;int fh; while(ch!='-'&&(ch>'9'||ch<'0')){ ch=getchar(); } if(ch=='-'){ fh=-1;ch=getchar(); }else fh=1; while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+ch-'0';ch=getchar(); } x*=fh; } inline char read1() { register char ch=getchar(); while(ch<'A'||ch>'M')ch=getchar(); return ch; } const int maxn=5e6+100; struct node{ int l,r; int s; int lazy; }t[maxn]; void build(int p,int l,int r){ t[p].l=l; t[p].r=r; if(l==r){ return ; } int mid=(l+r)/2; build(2*p,l,mid); build(2*p+1,mid+1,r); } void push(int p){ if(t[p].lazy){ t[2*p].s=(t[2*p].r-t[2*p].l+1)-t[2*p].s; t[2*p+1].s=(t[2*p+1].r-t[2*p+1].l+1)-t[2*p+1].s; t[2*p].lazy^=1; t[2*p+1].lazy^=1; t[p].lazy=0; } } void update(int p,int l,int r){ if(t[p].l>=l&&t[p].r<=r){ t[p].s=t[p].r-t[p].l+1-t[p].s; t[p].lazy^=1; return ; } if(t[p].lazy) push(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid){ update(2*p,l,r); } if(r>mid){ update(2*p+1,l,r); } t[p].s=t[2*p].s+t[2*p+1].s; } int query(int p,int l,int r){ if(t[p].l>=l&&t[p].r<=r){ return t[p].s; } int ans=0; if(t[p].lazy) push(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid){ ans+=query(2*p,l,r); } if(r>mid){ ans+=query(2*p+1,l,r); } return ans; } int n,m; int main(){ cin>>n>>m; int op,x,y; build(1,1,n); for(int i=1;i<=m;i++){ scanf("%d%d%d",&op,&x,&y); if(op==0){ update(1,x,y); } else if(op==1){ printf("%d ",query(1,x,y)); } } }
void push(int p){ if(t[p].lazy){ t[2*p].s=(t[2*p].r-t[2*p].l+1)-t[2*p].s; t[2*p+1].s=(t[2*p+1].r-t[2*p+1].l+1)-t[2*p+1].s; t[2*p].lazy=1; t[2*p+1].lazy=1; t[p].lazy=0; } } void update(int p,int l,int r){ int L=t[p].l,R=t[p].r; if(L>=l&&R<=r){ t[p].s=(R-L+1)-t[p].s; t[p].lazy=1; return ; }
这样有一个问题,就是
就是1-2区间变化两次,而这个区间是一整个节点没有在update中下传标记,在询问中下传标记时下传了一次,
本来该没有变化的,就是如果用异或的话询问两次的话,就变成0了,就不会出现上面的情况了
#pragma GCC optimize(1) #pragma GCC optimize(2) #pragma GCC optimize(3,"Ofast","inline") #include<bits/stdc++.h> using namespace std; typedef long long ll; template <typename Tp> void read(Tp &x){ x=0;char ch=1;int fh; while(ch!='-'&&(ch>'9'||ch<'0')){ ch=getchar(); } if(ch=='-'){ fh=-1;ch=getchar(); }else fh=1; while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+ch-'0';ch=getchar(); } x*=fh; } inline char read1() { register char ch=getchar(); while(ch<'A'||ch>'M')ch=getchar(); return ch; } const int maxn=5e6+100; struct node{ int l,r; int s; int lazy; }t[maxn]; void build(int p,int l,int r){ t[p].l=l; t[p].r=r; if(l==r){ return ; } int mid=(l+r)/2; build(2*p,l,mid); build(2*p+1,mid+1,r); } void push(int p){ if(t[p].lazy){ t[2*p].s=(t[2*p].r-t[2*p].l+1)-t[2*p].s; t[2*p+1].s=(t[2*p+1].r-t[2*p+1].l+1)-t[2*p+1].s; t[2*p].lazy^=1; t[2*p+1].lazy^=1; t[p].lazy=0; } } void update(int p,int l,int r){ if(t[p].l>=l&&t[p].r<=r){ t[p].s=t[p].r-t[p].l+1-t[p].s; t[p].lazy^=1; return ; } if(t[p].lazy) push(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid){ update(2*p,l,r); } if(r>mid){ update(2*p+1,l,r); } t[p].s=t[2*p].s+t[2*p+1].s; } int query(int p,int l,int r){ if(t[p].l>=l&&t[p].r<=r){ return t[p].s; } int ans=0; if(t[p].lazy) push(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid){ ans+=query(2*p,l,r); } if(r>mid){ ans+=query(2*p+1,l,r); } return ans; } int n,m; int main(){ cin>>n>>m; int op,x,y; build(1,1,n); for(int i=1;i<=m;i++){ scanf("%d%d%d",&op,&x,&y); if(op==0){ update(1,x,y); } else if(op==1){ printf("%d ",query(1,x,y)); } } }