#線段樹,離散#nssl 1476 聯
阿新 • • 發佈:2020-08-14
分析
由於下標過大,考慮離散,不僅僅是區間左右端點
假設只有一個區間從1到\(x\),那麼修改後答案應該是\(x+1\)
所以說還要記錄右端點+1的位置,你以為這就能A了嗎
為了避免標記被覆蓋,無論是否找到區間,都要下傳標記,並且如果當前標記為異或,
那麼在修改完之後原來的標記異或抵消,全0變全1,全1變全0,查詢就類似權值線段樹的方法就好了
時間複雜度\(O(nlog_2n)\)
程式碼
#include <cstdio> #include <cctype> #include <algorithm> #define rr register using namespace std; typedef long long lll; const int N=300011; int lazy[N<<2],z[N],m,n; lll w[N<<2],b[N],l[N],r[N]; inline lll iut(){ rr lll ans=0; rr char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } inline void print(lll ans){ if (ans>9) print(ans/10); putchar(ans%10+48); } inline void doit(int k,int l,int r,int z){ if (!z) return; if (z==1) w[k]=r-l+1; else if (z==2) w[k]=0; else w[k]=r-l+1-w[k]; if (z==3) lazy[k]^=z; else lazy[k]=z; } inline void pdown(int k,int l,int r){ if (!lazy[k]||l==r) return; rr int mid=(l+r)>>1; doit(k<<1,l,mid,lazy[k]); doit(k<<1|1,mid+1,r,lazy[k]); lazy[k]=0; } inline void update(int k,int l,int r,int x,int y,int z){ pdown(k,l,r); if (l==x&&r==y){doit(k,l,r,z); return;} rr int mid=(l+r)>>1; if (y<=mid) update(k<<1,l,mid,x,y,z); else if (x>mid) update(k<<1|1,mid+1,r,x,y,z); else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z); w[k]=w[k<<1]+w[k<<1|1]; } inline signed query(int k,int l,int r){ if (l==r) return l; rr int mid=(l+r)>>1; pdown(k,l,r); if (w[k<<1]==mid-l+1) return query(k<<1|1,mid+1,r); else return query(k<<1,l,mid); } signed main(){ m=iut(),b[n=1]=1; for (rr int i=1;i<=m;++i){ z[i]=iut(),l[i]=iut(),r[i]=iut(); b[++n]=l[i],b[++n]=r[i],b[++n]=r[i]+1; } sort(b+1,b+1+n),n=unique(b+1,b+1+n)-b-1; for (rr int i=1;i<=m;++i){ l[i]=lower_bound(b+1,b+1+n,l[i])-b; r[i]=lower_bound(b+1,b+1+n,r[i])-b; update(1,1,n,l[i],r[i],z[i]); print(b[query(1,1,n)]),putchar(10); } return 0; }