int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
int mn=sum[0];
for(int i=1;i<=n;i++){//枚举右端点
if(sum[i]-mn>ans)ans=sum[i]-mn;
if(mn>sum[i])mn=sum[i];
}
}
最优贸易简化版 倍增
3 --> 16
走13步=8+4+1
走1步 3 --> 4
走4步 4 --> 8
走8步 8 --> 16
需要预处理每个向后走2^i步的最优解
[3,4][4,5]
f[3][0]+f[4][0]=f[3][1]
[ L ][ R ]
更快的跳跃,从L走到R,需要走R-L步,把步数用二进制表示。
如果L到R需要走14步,L先走8步,到达L+8后再走4步,到达L+12后再走2步,到达R。
通过二进制数跳跃,每次跳过一段区间时,与分块类似。
需要预处理好每个点向后走2^j步的信息。
最小买入价格Mi[i][j]=min(Mi[i][j−1],Mi[i+2^(j−1)][j−1]);
最大卖出价格Mx[i][j]=max(Mx[i][j−1],Mx[i+2^(j−1)][j−1]);
最大收益F[i][j]=max{F[i][j−1],F[i+2^(j−1)][j−1],Mx[i+2^(j−1)][j−1]−Mi[i][j−1]};
单次询问的复杂度O(log n)
#include <bits/stdc++.h>
using namespace std;
int n,m,i,j,k,c[500005],ans[500005],v[500005][21],mi[500005][21],mx[500005][21];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1;i<+n;i++) mi[i][0]=mx[i][0]=c[i];
for(int i=1;(1<<i)<=n;i++){
for(int j=1;j<=n-(1<<i)+1;j++){
mi[j][i]=min(mi[j][i-1],mi[j+(1<<(i-1))][i-1]);
mx[j][i]=max(mx[j][i-1],mx[j+(1<<(i-1))][i-1]);
v[j][i]=max(max(v[j][i-1],v[j+(1<<(i-1))][i-1]),mx[j+(1<<(i-1))][i-1]-mi[j][i-1]);
}
}
for(int i=1;i<=m;i++){
int l,r;
scanf("%d%d",&l,&r);
int res=0,step=r-l,mn=c[l];
l++;
for(int j=0;(1<<j)<=step;j++){
if(step&(1<<j)){
res=max(res,max(v[l][j],mx[l][j]-mn));
mn=min(mn,mi[l][j]);
l+=1<<j;
}
}
printf("%d\n",res);
}
return 0;
}
最优贸易简化版 分块
把[L, R]分成很多块,枚举在每块中卖出,在之前的块中买入或者在当前块中买。
买入卖出发生在两个块时,需要知道第一块的最小值和第二个块的最大值,发生在一个块时,就需要知道这个块内最大值和最小值之差。
所以每个块就需要知道最大值、最小值、块内最大收益。
L R
... 〇〇|〇〇〇 〇〇〇〇〇 〇〇〇〇〇 〇〇|〇〇〇 ...
|_______| |_______| |______| |______|
块的大小为√n,两端最多扫描2√n个点,最多扫描√n个完整的块, 单次询问的复杂度为O(√n)。
#include<bits/stdc++.h>
int res;
int ma[n],mi[n],key[n];//数组下标代表其本身所代表组数的数据 key为当前组内本身能获得的最高利润
int job(int a,int b,int x,int a[]){
int qq=a/x;//起点所在区
int ww=b/x;//终点所在区
if(qq==ww){
int mi2=a[a];
for(int i=a+1,i<=b;i++){
res=max(res,a[i]-mi2);
mi=min(mi,a[i]);
}
}
else{
int mi2=a[a];
for(int i=a,i<(qq+1)*s){
res=max(res,a[i]-mi2);
mi=min(mi,a[i]);
}
for(int i=(qq+1)*s;i<=ww*s;i++){
res=max(max(key[x],res),ma[x]-mi2);
mi2=min(mi2,mi[x]);
}
for(int i=ww*s,i<=b,i++){
res=max(res,a[i]-mi2);
mi=min(mi,a[i]);
}
}
int main(){
int a[n];
int min=100000000,q;
res=0;
q=sqrt(n);
for(int i=0;i<=n;i++){
int x=n/q;//x是当前所计算数据所属组数
key[x]=max(key[x],a[i]-mi[x]);
mi[x]=min(min[x],a[i])
ma[x]=max(ma[a],a[i]);
}
最优贸易简化版 线段树
前两种做法,都是把这个区间划分成好几块,进行跳跃完成交易。
考虑分治,对于询问的区间,可以把区间分成[L,x]和[x+1,R]。
最终的答案肯定是这3种情况中的一种:
(1)在[L, x]中进行买卖
(2)[x + 1, R]中进行买卖
(3)在[L, x]中买入,在[x + 1, R]中卖出。
可以在线段树上把区间分开并且合并。存储的信息也是最小值,最大值和最优值。
单次询问的复杂度O(log n)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
struct node{
int l,r,mx,lm,rm;
}tree[100005<<2];
int n,m,t;
int a[100005];
void up(int rt){
tree[rt].lm=tree[rt<<1].lm;
tree[rt].rm=tree[rt<<1|1].rm;
tree[rt].mx=max(tree[rt<<1].mx,tree[rt<<1|1].mx);
int mid=(tree[rt].l+tree[rt].r)>>1;
if(a[mid]<a[mid+1]){
if (tree[rt<<1].lm==mid-tree[rt].l+1) tree[rt].lm+=tree[rt<<1|1].lm;
if (tree[rt<<1|1].rm==tree[rt].r-mid) tree[rt].rm+=tree[rt<<1].rm;
tree[rt].mx=max(tree[rt].mx,tree[rt<<1].rm+tree[rt<<1|1].lm);
}
}
void build(int rt,int l,int r){
tree[rt].l=l;
tree[rt].r=r;
if(l==r){
tree[rt].mx=tree[rt].lm=tree[rt].rm=1;
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
up(rt);
}
void update(int rt,int val,int p){
if (tree[rt].l==tree[rt].r){
a[p]=val;
return;
}
int mid=(tree[rt].l+tree[rt].r)>>1;
if (p<=mid) update(rt<<1,val,p);
else update(rt<<1|1,val,p);
up(rt);
}
int query(int rt,int l,int r){
if (l<=tree[rt].l&&tree[rt].r<=r) return tree[rt].mx;
int mid=(tree[rt].l+tree[rt].r)>>1;
int s=0;
if (l<=mid) s=max(s,query(rt<<1,l,r));
if (r>mid) s=max(s,query(rt<<1|1,l,r));
if (a[mid]<a[mid+1]){
s=max(s,min(tree[rt<<1].rm,mid-l+1)+min(tree[rt<<1|1].lm,r-mid));
}
return s;
}
signed main(){
cin>>t;
while (t--) {
cin>>n>>m;
for (int i=1;i<=n;i++) cin>>a[i];
build(1,1,n);
while (m--){
string s;
int x,y;
cin>>s>>x>>y;
if (s[0]=='Q')
cout<<query(1,x+1,y+1)<<endl;
else update(1,y,x+1);
}
}
return 0;
}
新能源汽车厂
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char op[100005];
ll a[100005],b[100005],ans;
int n,m;
ll suma[400005],sumb[400005],la[400005],lb[400005];
void builda(int l,int r,int rt){
if(l==r){
suma[rt]=a[l];
return;
}
int mid=(l+r)/2;
builda(l,mid,2*rt);
builda(mid+1,r,2*rt+1);
suma[rt]=suma[2*rt]+suma[2*rt+1];
}
ll querya(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R) return suma[rt];
int mid=(l+r)/2;
if(la[rt]>0){
la[2*rt]+=la[rt];
suma[2*rt]+=la[rt]*(mid-l+1);
la[2*rt+1]+=la[rt];
suma[2*rt+1]+=la[rt]*(r-mid-1+1);
la[rt]=0;
}
ll res=0,ret=0;
if(L<=mid) res=querya(L,R,l,mid,2*rt);
if(R>=mid+1) ret=querya(L,R,mid+1,r,2*rt+1);
return res+ret;
}
void updatea(int L,int R,int l,int r,int rt,ll val){
if(L<=l&&r<=R){
la[rt]+=val;
suma[rt]+=val*(r-l+1);
return;
}
int mid=(l+r)/2;
if(la[rt]>0){
la[2*rt]+=la[rt];
suma[2*rt]+=la[rt]*(mid-l+1);
la[2*rt+1]+=la[rt];
suma[2*rt+1]+=la[rt]*(r-mid-1+1);
la[rt]=0;
}
if(L<=mid) updatea(L,R,l,mid,2*rt,val);
if(R>=mid+1) updatea(L,R,mid+1,r,2*rt+1,val);
suma[rt]=suma[2*rt]+suma[2*rt+1];
}
void buildb(int l,int r,int rt){
if(l==r){
sumb[rt]=b[l];
lb[rt]=b[l];
return;
}
int mid=(l+r)/2;
buildb(l,mid,2*rt);
buildb(mid+1,r,2*rt+1);
sumb[rt]=sumb[2*rt]+sumb[2*rt+1];
}
ll queryb(int L,int R,int l,int r,int rt){
if(L<=l && r<=R) return sumb[rt];
int mid=(l+r)/2;
if(lb[rt]>0){
lb[2*rt]=lb[rt];
sumb[2*rt]=(mid-l+1)*lb[rt];
lb[2*rt+1]=lb[rt];
sumb[2*rt+1]=(r-mid-1+1)*lb[rt];
lb[rt]=0;
}
ll res=0,ret=0;
if(L<=mid) res=queryb(L,R,l,mid,2*rt);
if(R>=mid+1) ret=queryb(L,R,mid+1,r,2*rt+1);
return res+ret;
}
void updateb(int L,int R,int l,int r,int rt,ll val)
{
if(L<=l && r<=R){
lb[rt]=val;
sumb[rt]=val*(r-l+1);
return ;
}
int mid=(l+r)/2;
if(lb[rt]>0){
lb[2*rt]=lb[rt];
sumb[2*rt]=(mid-l+1)*lb[rt];
lb[2*rt+1]=lb[rt];
sumb[2*rt+1]=(r-mid-1+1)*lb[rt];
lb[rt]=0;
}
if(L<=mid) updateb(L,R,l,mid,2*rt,val);
if(R>=mid+1) updateb(L,R,mid+1,r,2*rt+1,val);
sumb[rt]=sumb[2*rt]+sumb[2*rt+1];
}
void handle(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
if(lb[rt]>0){
ans-=lb[rt]*querya(l,r,1,n,1);
return;
}
}
int mid=(l+r)/2;
if(lb[rt]>0){
lb[2*rt]=lb[rt];
sumb[2*rt]=(mid-l+1)*lb[rt];
lb[2*rt+1]=lb[rt];
sumb[2*rt+1]=(r-mid-1+1)*lb[rt];
lb[rt]=0;
}
if(L<=mid) handle(L,R,l,mid,2*rt);
if(R>=mid+1) handle(L,R,mid+1,r,2*rt+1);
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld %lld",&a[i],&b[i]);
ans+=a[i]*b[i];
}
builda(1,n,1);
buildb(1,n,1);
while(m--){
int l,r;ll x;
scanf("%s %d %d %lld",op,&l,&r,&x);
if(strcmp(op,"Add")==0){
ll cnt=queryb(l,r,1,n,1);
ans+=cnt*x;
updatea(l,r,1,n,1,x);
}
else{
handle(l,r,1,n,1);
ans+=x*querya(l,r,1,n,1);
updateb(l,r,1,n,1,x);
}
printf("%lld\n",ans);
}
return 0;
}
标签:rt,lb,la,int,mid,20240201,数据结构,sumb,随记
From: https://www.cnblogs.com/Firepaw-cattery/p/18004362