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∀1≤i≤nai=0 等价于∀1≤i≤ndi=0\forall_{1\leq i\leq n} d_i=0∀1≤i≤ndi=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}d1→n+1选两个数一个+1另一个-1。并且不难发现无论怎么进行上述操作总有∑i=1n+1di=0\sum_{i=1}^{n+1} d_i=0∑i=1n+1di=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−∣}=2∑i=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∀1≤i≤ndi+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}2∣di∣→2∣di+k∣,Δ=2k−2∣di∣
如果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}2∣di∣→2∣di−k∣,Δ=2k−2∣di∣
于是只需要把did_idi分为小于0的一组和大于0的一组,按照Δ=k−2∣di∣2\Delta=\frac{k-2|d_i|}{2}Δ=2k−2∣di∣从小到大排序,每次取两数组中开头的两个(Δ+)+(Δ−)(\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;
}