日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

2021牛客暑期多校训练营7 K-xay loves sequence(主席树+二分)

發布時間:2023/12/3 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2021牛客暑期多校训练营7 K-xay loves sequence(主席树+二分) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

K-xay loves sequence

首先不考慮模kkk的限制,容易想到對原數組做一個差分得到di=ai?ai?1d_i=a_i-a_{i-1}di?=ai??ai?1?,顯然對于?1≤i≤nai=0\forall_{1\leq i\leq n} a_i=0?1in?ai?=0 等價于?1≤i≤ndi=0\forall_{1\leq i\leq n} d_i=0?1in?di?=0,而對于原數組的區間±1\pm1±1等價于在差分數組ddd中找到兩個數一個數+1另一個數-1,或者說找到一個位置pos\text {pos}pos單獨+1或者-1(這意味著原數組[apos→an]±1[a_{\text{pos}}\to a_n] \pm1[apos?an?]±1)。上面的最優解顯然是max?{∑d+,∣∑d?∣}\max\{\sum d_+,|\sum{d_-}|\}max{d+?,d??}

上述變換有些麻煩,如果我們引入an+1=0a_{n+1}=0an+1?=0,并且引入dn+1=an+1?and_{n+1}=a_{n+1}-a_ndn+1?=an+1??an?后,對于原數組進行區間±1\pm1±1等價于在差分數組d1→n+1d_{1\to n+1}d1n+1?選兩個數一個+1另一個-1。并且不難發現無論怎么進行上述操作總有∑i=1n+1di=0\sum_{i=1}^{n+1} d_i=0i=1n+1?di?=0最優解max?{∑d+,∣∑d?∣}=∑i=1n+1∣di∣2\max\{\sum d_+,|\sum{d_-}|\}=\frac{\sum_{i=1}^{n+1} |d_i|}{2}max{d+?,d??}=2i=1n+1?di??


hipamp題解

考慮模kkk的意義下意味著我們可以花費0的代價使得某些ai±ka_i\pm kai?±k,對應在差分數組上即是di±k,di+1?kd_i\pm k,d_{i+1}\mp kdi?±k,di+1??k,換句話說現在可以讓成對的di±k,dj?kd_i\pm k,d_j\mp kdi?±k,dj??k最終結果仍然是讓?1≤i≤ndi+1=0\forall_{1\leq i\leq n} d_{i+1}=0?1in?di+1?=0。

不難發現di=di+kd_i=d_i+kdi?=di?+k那么一定有di<0d_i<0di?<0,同理di=di?kd_i=d_i-kdi?=di??k那么一定有di≥0d_i\ge0di?0

如果di=di+kd_i=d_i+kdi?=di?+k,那么貢獻從∣di∣2→∣di+k∣2,Δ=k?2∣di∣2\frac{|d_i|}{2}\to\frac{|d_i+k|}{2},\Delta=\frac{k-2|d_i|}{2}2di??2di?+k?,Δ=2k?2di??

如果di=di?kd_i=d_i-kdi?=di??k,那么貢獻從∣di∣2→∣di?k∣2,Δ=k?2∣di∣2\frac{|d_i|}{2}\to\frac{|d_i-k|}{2},\Delta=\frac{k-2|d_i|}{2}2di??2di??k?,Δ=2k?2di??

于是只需要把did_idi?分為小于0的一組和大于0的一組,按照Δ=k?2∣di∣2\Delta=\frac{k-2|d_i|}{2}Δ=2k?2di??從小到大排序,每次取兩數組中開頭的兩個(Δ+)+(Δ?)(\Delta_+)+(\Delta_-)(Δ+?)+(Δ??),如果能使答案變小即(Δ+)+(Δ?)<0(\Delta_+)+(\Delta_-)<0(Δ+?)+(Δ??)<0即一直取。


首先如果沒有區間l,rl,rl,r的限制,每次詢問只給一個kkk的話可以二分取了多少對d?+k,d+?kd_{-}+k,d_{+}-kd??+k,d+??k,快速的求出答案。顯然加上區間限制只需要套一個主席樹即可。

注意對于[l,r][l,r][l,r]區間來說差分數組是(al?0),dl+1,…dr,(0?ar)(a_l-0),d_{l+1},\dots d_{r},(0-a_r)(al??0),dl+1?,dr?,(0?ar?),也就是主席樹維護did_idi?,然后每次詢問會增添兩個數(al?0)(a_l-0)(al??0)(0?ar)(0-a_r)(0?ar?),一個插在正主席樹,一個在負主席樹。一個顯然的想法是單點修改2次,然后詢問過后刪除,就如下面注釋的代碼。但是主席樹不支持修改,因為修改不僅僅影響一棵主席樹,而是會影響許多棵樹,于是只需要在詢問的時候帶上這個數即可。

#include<bits/stdc++.h> using namespace std; using ll=long long; template <class T=int> T rd() {T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg; } const int N=200010; const int U=(1ll<<31)-1; int a[N],d[N]; ll s[N]; int n,m; struct node {int l,r;ll v,ct; }tree[N*100]; int rt[2][N],cnt; void update(int l,int r,int pre,int &u,int v,int c) {u=++cnt;tree[u]=tree[pre];tree[u].ct+=c;tree[u].v+=v*c;if(l==r) return;int mid=l+r>>1;if(v<=mid) update(l,mid,tree[pre].l,tree[u].l,v,c);elseupdate(mid+1,r,tree[pre].r,tree[u].r,v,c); } // void change(int &u,int l,int r,int v,int c) // { // if(!u) u=++cnt; // tree[u].ct+=c; // tree[u].v+=v*c; // if(l==r) return; // int mid=l+r>>1; // if(v<=mid) // change(tree[u].l,l,mid,v,c); // else // change(tree[u].r,mid+1,r,v,c); // } // // 求前k大的sum // ll query(int l,int r,int L,int R,int k) // { // if(!k) return 0ll; // if(l==r) return 1ll*k*l; // int mid=l+r>>1; // int tmp=tree[tree[R].r].ct-tree[tree[L].r].ct; // if(k<=tmp) // return query(mid+1,r,tree[L].r,tree[R].r,k); // else // return (1ll*tree[tree[R].r].v-tree[tree[L].r].v)+query(l,mid,tree[L].l,tree[R].l,k-tmp); // } // // 計算數組l~r的答案 取前k大 // ll calc(int l,int r,int k,int x) // { // // a[l]+d[l+1]~d[r]+abs(0-a[r])// ll v=(s[r]-s[l]+a[r]+a[l])/2; // ll s1=query(0,U,rt[0][l],rt[0][r],k); // ll s2=query(0,U,rt[1][l],rt[1][r],k); // return v-s1-s2+1ll*k*x; // } // 求前k大的sum ll query(int l,int r,int L,int R,int k,int v) {if(!k) return 0ll;if(l==r) return 1ll*k*l;int mid=l+r>>1;int tmp=tree[tree[R].r].ct-tree[tree[L].r].ct+(mid<v&&v<=r);if(k<=tmp) return query(mid+1,r,tree[L].r,tree[R].r,k,v);else return (1ll*tree[tree[R].r].v-tree[tree[L].r].v)+(mid<v&&v<=r)*v+query(l,mid,tree[L].l,tree[R].l,k-tmp,v); } // 計算數組l~r的答案 取前k大 ll calc(int l,int r,int k,int x) {// a[l]+d[l+1]~d[r]+abs(0-a[r])ll v=(s[r]-s[l]+a[r]+a[l])/2;ll s1=query(0,U,rt[0][l],rt[0][r],k,a[l]);ll s2=query(0,U,rt[1][l],rt[1][r],k,a[r]);return v-s1-s2+1ll*k*x; } int main() {n=rd(),m=rd();for(int i=1;i<=n;i++) {a[i]=rd();d[i]=abs(a[i]-a[i-1]);s[i]=s[i-1]+d[i];if(a[i]>=a[i-1]) {update(0,U,rt[0][i-1],rt[0][i],d[i],1);rt[1][i]=rt[1][i-1];}else{update(0,U,rt[1][i-1],rt[1][i],d[i],1);rt[0][i]=rt[0][i-1];}}while(m--){int x=rd(),y=rd(),k=rd();// a[x] d[x+1] d[x+2]... d[y] abs(0-a[y])// change(rt[0][y],0,U,a[x],+1);// change(rt[1][y],0,U,a[y],+1);int l=0,r=min(tree[rt[0][y]].ct-tree[rt[0][x]].ct,tree[rt[1][y]].ct-tree[rt[1][x]].ct)+1;//cout<<l<<' '<<r<<'\n';while(l<r){int mid=l+r>>1;if(calc(x,y,mid,k)<=calc(x,y,mid+1,k)) r=mid;else l=mid+1;}printf("%lld\n",calc(x,y,l,k));// change(rt[0][y],0,U,a[x],-1);// change(rt[1][y],0,U,a[y],-1);}return 0; }

總結

以上是生活随笔為你收集整理的2021牛客暑期多校训练营7 K-xay loves sequence(主席树+二分)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。