1. 程式人生 > >[JSOI2009]等差數列【差分+線段樹】

[JSOI2009]等差數列【差分+線段樹】

作為水到一等的弱省OI蒟蒻,甚至以為自己能聽懂SDWC的省選班。去了以後發現除了搜尋、仰望大佬和看妹子(還真有妹子很不錯)以外啥都不會…每天都是聽一小時之後棄療。
然而唯一有基礎的線段樹…也是一上來“大家都會寫線段樹吧”然後丟一道黑題(也就是這道)。同伴在身邊大呼簡單:“也就差分比較難想。”於是當天晚自習,我們點開了那道題…
寫完統計差分陣列中連續相等數的長度獲得了一堆Wonderful Answer後…發現正確答案比我們的輸出小一半後百思不得其解…點開題解,發現要維護什麼零散數列長度…同伴果斷放棄,我也知道考場上不可能有時間給你看題解,不過面對自己百餘行程式碼不忍棄之…然後懟了一週,終於a掉了。
唉,手殘毀一生,特此留念。

正文也沒啥可以寫的,各路大佬寫得都很透徹,我的碼力不足,常數巨大,那我總結一下看題解得到的經驗。

1.各路大佬都喜歡快讀,看來這種水平的題目,刷題者已經習慣快讀了;
2.當線段樹向上合併操作比較麻煩的時候,可以線上段樹節點的結構體中過載加號(我在這道題沒寫,導致pushup和query的時候寫了兩遍…);
3.差分陣列中第一項為原陣列第二項與第一項之差,以此類推,所以差分陣列中只有n-1個元素;
4.注意邊界問題的處理,區間加的時候看看邊界,比如第一項沒有與前一項的差什麼的;
5.千萬不能手殘!!!!!!!!!!!!!

#include<cstdio>
#include<algorithm> #define lll long long const lll maxn=100002; lll tt[maxn],a[maxn],n,m,x,y,s,t,i; char ch[3]; struct node{lll l,r,t,ll,rr,len;}; struct segtree{ #define lson (o<<1) #define rson (o<<1|1) #define mid ((l+r)>>1) lll addv[maxn<<2],vall[maxn<<2
],valr[maxn<<2],sumt[maxn<<2],suml[maxn<<2],sumr[maxn<<2],lenv[maxn<<2]; inline void pushup(lll o){ lll lenl=lenv[lson],lenr=lenv[rson]; lenv[o]=lenl+lenr;//此處手殘多處,有很多細節 suml[o]=sumr[o]=0; vall[o]=vall[lson];valr[o]=valr[rson];sumt[o]=sumt[lson]+sumt[rson]; if(suml[lson]==lenl&&sumr[rson]==lenr){ if(vall[rson]==valr[lson]){sumt[o]=1;suml[o]=lenl-1;sumr[o]=lenr-1;} else{sumt[o]=0;suml[o]=sumr[o]=lenv[o];} return; } if(suml[lson]==lenl&&sumr[rson]!=lenr){ sumr[o]=sumr[rson]; if(vall[rson]==valr[lson]){suml[o]=lenl-1;if(suml[rson]>0)sumt[o]+=(suml[rson]-1)/2+1;}//此處手殘打錯一個字元,wa一半也是很絕望(資料也是挺水...能讓我過一半) else suml[o]=suml[lson]+suml[rson]; return; } if(sumr[rson]==lenr&&sumr[lson]!=lenl){ suml[o]=suml[lson]; if(vall[rson]==valr[lson]){sumr[o]=lenr-1;if(sumr[lson]>0)sumt[o]+=(sumr[lson]-1)/2+1;} else sumr[o]=sumr[lson]+sumr[rson]; return; } suml[o]=suml[lson];sumr[o]=sumr[rson]; if(suml[rson]==0&&sumr[lson]==0){ if(vall[rson]==valr[lson])sumt[o]--; return; } if(sumr[lson]==0&&suml[rson]!=0){ if(vall[rson]==valr[lson])sumt[o]+=(suml[rson]-1)/2; else sumt[o]+=suml[rson]/2; return; } if(sumr[lson]!=0&&suml[rson]==0){ if(vall[rson]==valr[lson])sumt[o]+=(sumr[lson]-1)/2; else sumt[o]+=sumr[lson]/2; return; } if(vall[rson]==valr[lson])sumt[o]+=std::min((suml[rson]+sumr[lson])/2,(suml[rson]-1)/2+(sumr[lson]-1)/2+1); else sumt[o]+=(suml[rson]+sumr[lson])/2; } inline void pushdown(lll o){ addv[lson]+=addv[o];addv[rson]+=addv[o]; vall[lson]+=addv[o];vall[rson]+=addv[o]; valr[lson]+=addv[o];valr[rson]+=addv[o]; addv[o]=0; } inline void build(lll o,lll l,lll r){ if(l==r){vall[o]=valr[o]=a[l];suml[o]=sumr[o]=lenv[o]=1;sumt[o]=addv[o]=0;return;} build(lson,l,mid); build(rson,mid+1,r); pushup(o); } inline node querysum(lll o,lll l,lll r,lll ql,lll qr){ if(ql<=l&&qr>=r)return (node){vall[o],valr[o],sumt[o],suml[o],sumr[o],lenv[o]}; pushdown(o); if(qr<=mid)return querysum(lson,l,mid,ql,qr); else if(ql>mid)return querysum(rson,mid+1,r,ql,qr); else{ node ans,ll,rr;//這裡又要打一遍,以後注意過載加號 ll=querysum(lson,l,mid,ql,qr); rr=querysum(rson,mid+1,r,ql,qr); lll lenl=ll.len,lenr=rr.len; ans.ll=ans.rr=0; ans.l=ll.l;ans.r=rr.r;ans.t=ll.t+rr.t;ans.len=ll.len+rr.len; if(ll.ll==lenl&&rr.rr==lenr){ if(rr.l==ll.r){ans.t=1;ans.ll=lenl-1;ans.rr=lenr-1;} else{ans.t=0;ans.ll=ans.rr=ans.len;} return ans; } if(ll.ll==lenl&&rr.rr!=lenr){ ans.rr=rr.rr; if(rr.l==ll.r){ans.ll=lenl-1;if(rr.ll>0)ans.t+=(rr.ll-1)/2+1;} else ans.ll=ll.ll+rr.ll; return ans; } if(rr.rr==lenr&&ll.rr!=lenl){ ans.ll=ll.ll; if(rr.l==ll.r){ans.rr=lenr-1;if(ll.rr>0)ans.t+=(ll.rr-1)/2+1;} else ans.rr=ll.rr+rr.rr; return ans; } ans.ll=ll.ll;ans.rr=rr.rr; if(rr.ll==0&&ll.rr==0){ if(rr.l==ll.r)ans.t--; return ans; } if(ll.rr==0&&rr.ll!=0){ if(rr.l==ll.r)ans.t+=(rr.ll-1)/2; else ans.t+=rr.ll/2; return ans; } if(ll.rr!=0&&rr.ll==0){ if(rr.l==ll.r)ans.t+=(ll.rr-1)/2; else ans.t+=ll.rr/2; return ans; } if(rr.l==ll.r)ans.t+=std::min((rr.ll+ll.rr)/2,(rr.ll-1)/2+(ll.rr-1)/2+1); else ans.t+=(rr.ll+ll.rr)/2; return ans; } } inline void optadd(lll o,lll l,lll r,lll ql,lll qr,lll v){ if(ql<=l&&qr>=r){vall[o]+=v;valr[o]+=v;addv[o]+=v;return;} pushdown(o); if(ql<=mid)optadd(lson,l,mid,ql,qr,v); if(qr>mid)optadd(rson,mid+1,r,ql,qr,v); pushup(o); } }seg; int main(){ scanf("%lld",&n); for(i=1;i<=n;i++)scanf("%lld",&tt[i]); for(i=1;i<n;i++)a[i]=tt[i+1]-tt[i]; n--;//懶得處理了,直接-- seg.build(1,1,n); scanf("%lld",&m); while(m--){ scanf("%s",&ch); if(ch[0]=='A'){ scanf("%lld%lld%lld%lld",&x,&y,&s,&t); if(x>1)seg.optadd(1,1,n,x-1,x-1,s); if(x<y)seg.optadd(1,1,n,x,y-1,t); if(y<=n)seg.optadd(1,1,n,y,y,-s-(y-x)*t); }else{ scanf("%lld%lld",&x,&y); node fff; if(x==y){printf("1\n");continue;} fff=seg.querysum(1,1,n,x,y-1); if(fff.t==0)printf("%lld\n",(y-x+2)/2); else printf("%lld\n",std::min((y-x+2)/2,fff.t+(fff.ll+1)/2+(fff.rr+1)/2)); } } return 0; }

這就屬於線段樹裡的難題了吧…以後這種不符合我能力的題,少碰…至於那道毒瘤的交通路線題…日後再說。

下一步填一下網路流的坑,問了問對面zhhx大佬,他初中就會網路流了…%%%差距很大啊,革命尚未成功…祝我一個月以後的省選能取得一個好成績,到時候去食堂弄十條炸肉捆起來擺在孔夫子面前,嗯…吾未嘗無誨焉。
網路流大概也是個大坑,數學建模能力…嗯就這樣。