洛谷 P3870 [TJOI2009]開關
阿新 • • 發佈:2018-12-26
題目描述
現有\(N(2 ≤ N ≤ 100000)\)盞燈排成一排,從左到右依次編號為:\(1,2,......,N\)。然後依次執行\(M(1 ≤ M ≤ 100000)\)項操作,操作分為兩種:第一種操作指定一個區間\([a, b]\),然後改變編號在這個區間內的燈的狀態(把開著的燈關上,關著的燈開啟),第二種操作是指定一個區間\([a, b]\),要求你輸出這個區間內有多少盞燈是開啟的。燈在初始時都是關著的。
輸入輸出格式
輸入格式:
第一行有兩個整數\(N\)和\(M\),分別表示燈的數目和操作的數目。接下來有\(M\)行,每行有三個整數,依次為:\(c, a, b\)。其中\(c\)表示操作的種類,當\(c\)
輸出格式:
每當遇到第二種操作時,輸出一行,包含一個整數:此時在查詢的區間中開啟的燈的數目。
輸入輸出樣例
輸入樣例#1:
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4
輸出樣例#1:
1
2
思路:還是一道線段樹區間異或,思路跟之前做的洛谷P2574和洛谷P2846完全一樣。
程式碼:
#include<cstdio> #include<cctype> #define maxn 100007 #define ls rt<<1 #define rs rt<<1|1 using namespace std; int n,m,sum[maxn<<2],lazy[maxn<<2]; inline int qread() { char c=getchar();int num=0,f=1; for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num*f; } inline void pushup(int rt) { sum[rt]=sum[ls]+sum[rs]; } inline void pushdown(int rt, int len) { if(lazy[rt]) { lazy[ls]^=1; lazy[rs]^=1; sum[ls]=(len-(len>>1))-sum[ls]; sum[rs]=(len>>1)-sum[rs]; lazy[rt]=0; } } void modify(int rt, int l, int r, int L, int R) { if(L>r||R<l) return; if(L<=l&&r<=R) { lazy[rt]^=1; sum[rt]=r-l+1-sum[rt]; return; } pushdown(rt,r-l+1); int mid=(l+r)>>1; modify(ls,l,mid,L,R),modify(rs,mid+1,r,L,R); pushup(rt); } int csum(int rt, int l, int r, int L, int R) { if(L>r||R<l) return 0; if(L<=l&&r<=R) return sum[rt]; pushdown(rt,r-l+1); int mid=(l+r)>>1; return csum(ls,l,mid,L,R)+csum(rs,mid+1,r,L,R); } int main() { n=qread(),m=qread(); for(int i=1,k,l,r;i<=m;++i) { k=qread(),l=qread(),r=qread(); if(!k) modify(1,1,n,l,r); else printf("%d\n",csum(1,1,n,l,r)); } return 0; }