最优贸易简化版

来源:互联网 发布:有多少网络交易平台 编辑:程序博客网 时间:2024/05/21 10:28

最优贸易简化版

题目描述 C国有 nn 座城市,编号是 11 到 nn ,编号为 ii 的城市有路到编号为 i+1i+1 的城市(编号为 nn
的城市没有路到其他的城市)。
C国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。
商人阿龙再次来到C国旅游。他还是想贩卖水晶赚取旅费,在某个城市买入,再另一个城市卖出。
他将从编号为 aa 的城市到编号到 bb 的城市。请你帮他算算,最多能赚多少钱。
注:他最多进行一次买入和一次卖出。
输入 第一行两个整数 nn 和 mm ,表示 nn 个城市和 mm 个询问。
第二行 n个整数,表示 n 座城市水晶的买入和卖出的价格。接下来 mm 行,每行两个整数 a,b ,表示阿龙要从编号为 a的城市到编号为 b的城市(a小于b)
输出 对于每个询问输出阿龙能赚多少钱。

一.并查集

通过离线对询问进行处理,然后由1扫描至n,利用getfa函数对数据进行处理
复杂度为O(n+m)【最快】

#include<cstdio>#include<iostream>#include<vector>using namespace std;#define M 500005#define FOR(i,x,y) for(int i=(x);i<(y);i++)typedef pair<int,int>P;vector<P>q[M];int par[M],mx[M],mi[M],res[M],A[M],ans[M];int getfa(int x){    if(par[x]==x)return x;    int t=par[x];    par[x]=getfa(par[x]);    if(res[x]<mx[t]-mi[x])res[x]=mx[t]-mi[x];    if(res[x]<res[t])res[x]=res[t];    if(mi[x]>mi[t])mi[x]=mi[t];    if(mx[x]<mx[t])mx[x]=mx[t];    return par[x];}inline void Rd(int &res){    res=0;char c;    while(c=getchar(),c<47);    do res=(res<<3)+(res<<1)+(c&15);    while(c=getchar(),c>=48);}int main(){    int n,m;    Rd(n),Rd(m);    FOR(i,1,n+1)Rd(A[i]);    FOR(i,1,m+1){//离线        int x,y;         Rd(x),Rd(y);        P t;t.first=x,t.second=i;        q[y].push_back(t);    }    FOR(i,1,n+1){par[i]=i;mx[i]=mi[i]=A[i];}//初始化     FOR(i,1,n+1){        FOR(j,0,q[i].size()){            getfa(q[i][j].first);            ans[q[i][j].second]=res[q[i][j].first];        }        par[i]=i+1;    }    FOR(i,1,m+1)printf("%d\n",ans[i]);    return 0;}

二.线段树

通用的状态转移方程为:

void up(node &fa,node& l,node& r){    fa.res=max(l.res,r.res);    fa.res=max(r.mx-l.mi);    fa.mi=min(l.mi,r.mi);    fa.mx=max(l.mx,r.mx);}

然后就是裸的线段树,套个模板就好了

三.分块

其实也秉承了线段树up的思想,经过优化n^3/2也可以过
耗时

#include<cstdio>#include<cmath>using namespace std;#define FOR(i,x,y) for(int i=(x);i<=(y);i++)#define M 500005int A[M];struct node{    int mx,mi,v;}B[M];void init(int n,int s){    FOR(i,0,n/s){        B[i].mi=1e9;        B[i].mx=0;        B[i].v=0;       }    FOR(i,1,n){        if(A[i]-B[i/s].mi>B[i/s].v)B[i/s].v=A[i]-B[i/s].mi;        if(B[i/s].mi>A[i])B[i/s].mi=A[i];        if(B[i/s].mx<A[i])B[i/s].mx=A[i];    }}int main(){    int n,m;    scanf("%d%d",&n,&m);    FOR(i,1,n)scanf("%d",&A[i]);    init(n,sqrt(n));    int s=sqrt(n);    while(m--){        int x,y;        scanf("%d%d",&x,&y);        int ka=x/s,kb=y/s,ans=0;        if(ka==kb){            int mi=1e9;            FOR(i,x,y){                if(A[i]-mi>ans)ans=A[i]-mi;                if(A[i]<mi)mi=A[i];            }        }        else{            int mi=1e9;            FOR(i,x,(ka+1)*s-1){                if(A[i]-mi>ans)ans=A[i]-mi;                if(A[i]<mi)mi=A[i];            }            FOR(i,ka+1,kb-1){                if(B[i].mx-mi>ans)ans=B[i].mx-mi;                if(B[i].v>ans)ans=B[i].v;                if(B[i].mi<mi)mi=B[i].mi;            }            FOR(i,kb*s,y){                if(A[i]-mi>ans)ans=A[i]-mi;                if(A[i]<mi)mi=A[i];              }        }         printf("%d\n",ans);    }    return 0;}

四.倍增

实现起来与分块相似
但复杂度为nlog(n)

贴上部分代码

预处理

FOR(i,1,n){    mx[i][0]=max(A[i],A[i+1]);    mi[i][0]=min(A[i],A[i+1]);    val[i][0]=max(val[i][0],A[i+1]-A[i]);}FOR(j,1,S-1){    FOR(i,1,n){        if(i+(1<<j-1)>n)continue;        mx[i][j]=max(mx[i][j-1],mx[i+(1<<j-1)][j-1]);        mi[i][j]=min(mi[i][j-1],mi[i+(1<<j-1)][j-1]);        val[i][j]=max(val[i][j-1],val[i+(1<<j-1)][j-1]);        val[i][j]=max(val[i][j],mx[i+(1<<j-1)][j-1]-mi[i][j-1]);    }}

solve

int len=y-x,mn=1e9,ans=0;FOR(i,0,S-1){    if(len&1<<i){           ans=max(ans,val[x][i]);        ans=max(ans,mx[x][i]-mn);                   mn=min(mn,mi[x][i]);        x+=1<<i;    }}
原创粉丝点击