1. 程式人生 > >BZOJ4592 SHOI2015腦洞治療儀(線段樹)

BZOJ4592 SHOI2015腦洞治療儀(線段樹)

  考慮需要資瓷哪些操作:區間賦值為0;統計區間1的個數;將區間前k個0變為1;詢問區間最長全0子串。於是線段樹維護區間1的個數、0的個數、最長字首字尾全0子串即可。稍微困難的是用一個log實現將區間前k個0變為1,線段樹上二分儘量往左邊改即可,可以令修改函式返回值為剩餘能改的1的個數。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace
std; #define ll long long #define N 200010 int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } char getc(){char c=getchar();while ((c<'A'||c>'
Z')&&(c<'a'||c>'z')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int n,m,L[N<<2],R[N<<2]; struct data{int sum0,sum1,pre,suf,len,lazy; }tree[N<<2]; void update(int k,int x) { if (x==0) { tree[k].sum0=tree[k].pre=tree[k].suf=tree[k].len=R[k]-L[k]+1
; tree[k].sum1=0; } else { tree[k].sum0=tree[k].pre=tree[k].suf=tree[k].len=0; tree[k].sum1=R[k]-L[k]+1; } tree[k].lazy=x; } void up(int k) { tree[k].sum0=tree[k<<1].sum0+tree[k<<1|1].sum0; tree[k].sum1=tree[k<<1].sum1+tree[k<<1|1].sum1; if (tree[k<<1].pre==R[k<<1]-L[k<<1]+1) tree[k].pre=tree[k<<1].pre+tree[k<<1|1].pre; else tree[k].pre=tree[k<<1].pre; if (tree[k<<1|1].suf==R[k<<1|1]-L[k<<1|1]+1) tree[k].suf=tree[k<<1|1].suf+tree[k<<1].suf; else tree[k].suf=tree[k<<1|1].suf; tree[k].len=max(max(tree[k<<1].len,tree[k<<1|1].len),tree[k<<1].suf+tree[k<<1|1].pre); } void down(int k) { update(k<<1,tree[k].lazy); update(k<<1|1,tree[k].lazy); tree[k].lazy=-1; } void build(int k,int l,int r) { L[k]=l,R[k]=r;tree[k].lazy=-1; if (l==r) {tree[k].sum1=1;return;} int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); up(k); } void modify(int k,int l,int r) { if (L[k]==l&&R[k]==r) {update(k,0);return;} if (~tree[k].lazy) down(k); int mid=L[k]+R[k]>>1; if (r<=mid) modify(k<<1,l,r); else if (l>mid) modify(k<<1|1,l,r); else modify(k<<1,l,mid),modify(k<<1|1,mid+1,r); up(k); } int calc(int k,int l,int r) { if (L[k]==l&&R[k]==r) return tree[k].sum1; if (~tree[k].lazy) down(k); int mid=L[k]+R[k]>>1; if (r<=mid) return calc(k<<1,l,r); else if (l>mid) return calc(k<<1|1,l,r); else return calc(k<<1,l,mid)+calc(k<<1|1,mid+1,r); } int query(int k,int l,int r) { if (L[k]==l&&R[k]==r) return tree[k].len; if (~tree[k].lazy) down(k); int mid=L[k]+R[k]>>1; if (r<=mid) return query(k<<1,l,r); else if (l>mid) return query(k<<1|1,l,r); else return max(max(query(k<<1,l,mid),query(k<<1|1,mid+1,r)),min(tree[k<<1].suf,mid-l+1)+min(tree[k<<1|1].pre,r-mid)); } int paint(int k,int l,int r,int x) { if (!x) return 0; if (L[k]==l&&R[k]==r&&x>=tree[k].sum0) {x-=tree[k].sum0;update(k,1);return x;} if (~tree[k].lazy) down(k); int mid=L[k]+R[k]>>1; if (r<=mid) x=paint(k<<1,l,r,x); else if (l>mid) x=paint(k<<1|1,l,r,x); else { int t=paint(k<<1,l,mid,x); if (t>=0) x=paint(k<<1|1,mid+1,r,t); else x=0; } up(k); return x; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4592.in","r",stdin); freopen("bzoj4592.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); build(1,1,n); while (m--) { int op=read(),l=read(),r=read(); if (op==0) modify(1,l,r); else if (op==1) { int x=read(),y=read(); int k=calc(1,l,r); modify(1,l,r); paint(1,x,y,k); } else printf("%d\n",query(1,l,r)); } return 0; }