如下時空限制來自zoj
Time limit 10000 ms
Memory limit 32768 kB
OS Linux
Source Online Contest of Christopher's Adventure
Author XIN, Taohtml
zoj卡空間卡得太死了……32MB,遠遠不夠放沒優化過的主席樹套樹狀數組……剛開始時段錯誤,還覺得是t數組沒開夠,仍是學得不紮實,別人說是就是,都沒本身想一想算算……後來二分騙數據,發如今還沒開始操做、正在建最初的主席樹時空間就爆了。沒有優化的主席樹,t數組要開到N*100左右,但這題最多給開到N*40……因此逼着咱們優化空間。數組
平臺 | n | m | 空間限制 |
---|---|---|---|
洛谷 | 1e5 | 1e5 | 1000MB |
BZOJ | 1e4 | 1e4 | 128MB |
ZOJ | 5e4 | 1e4 | 32MB |
這個是我在BZOJ(本機測的darkbzoj數據,把N和M改小便可)、洛谷上的AC代碼,主要參考洛谷zsy的題解。ZOJ的留坑,打算把優化空間的方法、總體二分、cdq分治學了。函數
// luogu-judger-enable-o2 #include<stdio.h> #include<string.h> #include<algorithm> const int N=100010,M=100010; int T; int n,m; int a[N]; struct Opt{ char mode; int l,r,k; }opt[M]; int val[N+M],sz; int id(int x){return std::lower_bound(val+1,val+sz+1,x)-val;} struct Node{ int lson,rson; long long sum; }t[N*400]; int root[N],cnt=0; int inline lowbit(int x){return x&-x;} void update_tree(int &x,int l,int r,int pos,int k) {//pre好像不須要啊,第x個節點的值並不用從pre繼承過來,由於套上樹狀數組之後就不是前綴和了。參考zsy博客 if(!x) x=cnt++;//x等於0說明還沒分配過 t[x].sum+=k; if(l==r) return; int mid=l+r>>1; if(pos<=mid) update_tree(t[x].lson,l,mid,pos,k); else update_tree(t[x].rson,mid+1,r,pos,k); } void change(int pos,int k)//數字a[pos]數量加k(先把以前的值去掉) { int value=id(a[pos]); for(int i=pos;i<=n;i+=lowbit(i)) update_tree(root[i],1,sz,value,k); } int temp[2][20]; //記錄詢問時須要統計的節點編號,由於根有root數組,能夠root[x-lowbit(x)],但下來的兒子孫子節點不能,因此先把須要統計的根記錄在temp數組中,而後統計完一層之後將temp數組記錄的節點向下挪動。 //temp[0]記錄第l-1棵線段樹上的節點編號,temp[1]記錄第r棵線段樹上的節點編號。 //因爲節點已經存到temp中了,因此que_tree函數的參數就少了不少了。 int que_tree(int l,int r,int k) { if(l==r) return l; int mid=l+r>>1,delta=0; for(int i=1;i<=temp[1][0];i++) delta+=t[t[temp[1][i]].lson].sum; for(int i=1;i<=temp[0][0];i++) delta-=t[t[temp[0][i]].lson].sum;//統計那幾棵樹的左兒子的sum,用來和k比較,找出從左仍是從右 if(k<=delta)//向左走 { for(int i=1;i<=temp[0][0];i++) temp[0][i]=t[temp[0][i]].lson; for(int i=1;i<=temp[1][0];i++) temp[1][i]=t[temp[1][i]].lson;//temp也向下走 return que_tree(l,mid,k); } else { for(int i=1;i<=temp[0][0];i++) temp[0][i]=t[temp[0][i]].rson; for(int i=1;i<=temp[1][0];i++) temp[1][i]=t[temp[1][i]].rson; return que_tree(mid+1,r,k-delta); } } int que(int l,int r,int k) { temp[0][0]=temp[1][0]=0;//用於統計temp[0]和temp[1]中存了多少個節點下標 for(int i=l-1;i;i-=lowbit(i)) temp[0][++temp[0][0]]=root[i]; for(int i=r;i;i-=lowbit(i)) temp[1][++temp[1][0]]=root[i]; return que_tree(1,sz,k); } /******************調試代碼******************/ //用於輸出主席樹上每棵線段樹所表明的序列 int quesum(int x,int l,int r,int pos) { if(l==pos&&pos==r) return t[x].sum; int mid=l+r>>1; if(pos<=mid) return quesum(t[x].lson,l,mid,pos); else return quesum(t[x].rson,mid+1,r,pos); } inline void debug() { for (int i = 1; i <= sz; i++) printf("%d ", val[i]); puts("\n****************"); for (int rt = 0; rt <= n; rt++, puts("")) for (int i = 1; i <= sz; i++) printf("%d ", quesum(root[rt], 1, sz, i)); puts("******************"); } /*******************調試代碼完*****************/ int main() { //freopen("test.in","r",stdin); //scanf("%d",&T); //while(T--) { sz=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",a+i),val[++sz]=a[i]; for(int i=1;i<=m;i++) { char mode[2]; int l,r,k; scanf("%s",mode); if(mode[0]=='Q') { scanf("%d%d%d",&l,&r,&k); opt[i]={mode[0],l,r,k}; } else { scanf("%d%d",&l,&k); opt[i]={mode[0],l,0,k}; val[++sz]=k; } } std::sort(val+1,val+1+sz); sz=std::unique(val+1,val+sz+1)-val-1; //memset(root,0,sizeof(root)); //memset(t,0,sizeof(t)); cnt=1; for(int i=1;i<=n;i++) change(i,1); //debug(); for(int i=1;i<=m;i++) { if(opt[i].mode=='Q') { printf("%d\n",val[que(opt[i].l,opt[i].r,opt[i].k)]); } else { change(opt[i].l,-1); a[opt[i].l] = opt[i].k; change(opt[i].l,1); //debug(); } } } return 0; }