【BZOJ4942】[Noi2017]整數 線段樹+DFS(卡過)
阿新 • • 發佈:2017-07-25
push 正常的 int 描述 printf turn n-1 如果 bzoj
【BZOJ4942】[Noi2017]整數
題目描述去uoj
題解:如果只有加法,那麽直接暴力即可。。。(因為1的數量最多nlogn個)
先考慮加法,比較顯然的做法就是將A二進制分解成log位,然後依次更新這log位,如果最高位依然有進位,那麽找到最高位後面的第一個0,將中間的所有1變成0,那個0變成1。這個顯然要用到線段樹,但是復雜度是nlog2n的,肯定過不去。
於是我在考場上yy了一下,這log位是連續的,我們每次都要花費log的時間去修改一個豈不是很浪費?我們可以先在線段樹上找到這段區間,然後在線段樹上dfs下去,這樣,時間復雜度就變成O(logn+那段區間在線段樹上的大小)。因為一顆正常的線段樹的大小就是4*n的,而這裏的那段區間的大小是log的,所以我猜測復雜度應該是log*常數的。但是不會證,考完試旁邊的大佬都十分懷疑我的復雜度,搞得我也非常懷疑,但是。。但是AC了。
正解貌似是O(nlog2n/32)的線段樹+壓位?聽說考場上這麽寫的全被卡常了,體會到了wys的險惡用心~
回來重碼了一發,交到uoj上TLE了,交到BZ上AC了(因為是均攤復雜度嘛~)。
歡迎大佬告訴我這個算法的真正復雜度~
#include <cstdio> #include <cstring> #include <iostream> #define lson x<<1 #define rson x<<1|1 using namespace std; const int N=30000040; int n,A,B,nxt,f,len; int s[N+1<<2],p[50]; void pushdown(int l,int r,int x) { if(!s[x]) s[lson]=s[rson]=0; if(s[x]==r-l+1) { int mid=l+r>>1; s[lson]=mid-l+1,s[rson]=r-mid; } } void pushup(int x) { s[x]=s[lson]+s[rson]; } void dfs(int l,int r,int x) { if(l==r) { s[x]+=p[l-B]; while(s[x]>1) p[l-B+1]++,s[x]-=2; while(s[x]<0) p[l-B+1]--,s[x]+=2; return ; } pushdown(l,r,x); int mid=l+r>>1; dfs(l,mid,lson),dfs(mid+1,r,rson); pushup(x); } void updata(int l,int r,int x,int a,int b) { if(a<=l&&r<=b) { dfs(l,r,x); return ; } pushdown(l,r,x); int mid=l+r>>1; if(a<=mid) updata(l,mid,lson,a,b); if(b>mid) updata(mid+1,r,rson,a,b); pushup(x); } void modify(int l,int r,int x,int a,int b,int c) { if(a>b) return ; if(a<=l&&r<=b) { s[x]=(r-l+1)*c; return ; } pushdown(l,r,x); int mid=l+r>>1; if(a<=mid) modify(l,mid,lson,a,b,c); if(b>mid) modify(mid+1,r,rson,a,b,c); pushup(x); } void nxt0(int l,int r,int x,int a) { if(r<a||nxt<=l||s[x]==r-l+1) return ; if(l==r) { nxt=l; return ; } int mid=l+r>>1; pushdown(l,r,x); nxt0(l,mid,lson,a),nxt0(mid+1,r,rson,a); } void nxt1(int l,int r,int x,int a) { if(r<a||nxt<=l||!s[x]) return ; if(l==r) { nxt=l; return ; } int mid=l+r>>1; pushdown(l,r,x); nxt1(l,mid,lson,a),nxt1(mid+1,r,rson,a); } int query(int l,int r,int x,int a) { if(l==r) return s[x]; pushdown(l,r,x); int mid=l+r>>1; if(a<=mid) return query(l,mid,lson,a); return query(mid+1,r,rson,a); } int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘) f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } int main() { n=rd(),rd(),rd(),rd(); int i; for(i=1;i<=n;i++) { if(rd()==1) { A=rd(),B=rd(),f=1,len=0; if(!A) continue; if(A<0) f=-1,A=-A; while(A) p[len++]=(A&1)*f,A>>=1; p[len++]=0,p[len]=0,updata(0,N,1,B,B+len-1); if(p[len]>0) { nxt=1<<30,nxt0(0,N,1,B+len); modify(0,N,1,B+len,nxt-1,0),modify(0,N,1,nxt,nxt,1); } if(p[len]<0) { nxt=1<<30,nxt1(0,N,1,B+len); modify(0,N,1,B+len,nxt-1,1),modify(0,N,1,nxt,nxt,0); } } else A=rd(),printf("%d\n",query(0,N,1,A)); } return 0; } //10 3 1 2 1 100 0 1 2333 0 1 -233 0 2 5 2 7 2 15 1 5 15 2 15 1 -1 12 2 15
【BZOJ4942】[Noi2017]整數 線段樹+DFS(卡過)