[arc067f]Yakiniku Restaurants

来源:互联网 发布:win10磁盘碎片整理软件 编辑:程序博客网 时间:2024/06/15 11:32

题目大意

不想讲。

做法

大概是需要知道如何给一个区间包含的所有区间打加法tag。
给[l,r]包含的所有区间+d,可以令v[l,r]+d。
最终做一遍v[l,r]+=v[l-1,r]+v[l,r+1]-v[l-1,r+1]。
容易讨论这是对的。
这题做m次,建关于最大值的笛卡尔树,那么每次相当于一个区间包含的区间中包含某个位置的可以加多少,可以转化为三个包含区间加法。

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;const int maxn=5000+10,maxm=200+10;ll v[maxn][maxn],d[maxn];int b[maxm][maxn],a[maxn];int sta[maxn],fa[maxn],lc[maxn],rc[maxn],L[maxn],R[maxn];int i,j,k,l,t,n,m,top,root;ll ans;void ins(int mid,int l,int r,int x){    v[l][r]+=(ll)x;    v[l][mid-1]-=(ll)x;    v[mid+1][r]-=(ll)x;}void dfs(int x){    L[x]=R[x]=x;    if (lc[x]){        dfs(lc[x]);        L[x]=L[lc[x]];    }    if (rc[x]){        dfs(rc[x]);        R[x]=R[rc[x]];    }    ins(x,L[x],R[x],a[x]);}void work(int id){    int i,j;    fo(i,1,n) a[i]=b[id][i];    fo(i,1,n) fa[i]=lc[i]=rc[i]=0;    top=0;    fo(i,1,n){        while (top&&a[i]>a[sta[top]]){            if (fa[sta[top]]) rc[sta[top]]=i;            rc[sta[top]]=lc[i];            lc[i]=sta[top];            top--;        }        fa[i]=sta[top];        rc[sta[top]]=i;        sta[++top]=i;    }    root=sta[1];    dfs(root);}int main(){    scanf("%d%d",&n,&m);    fo(i,2,n){        scanf("%d",&d[i]);        d[i]+=d[i-1];    }    fo(i,1,n)        fo(j,1,m) scanf("%d",&b[j][i]);    fo(i,1,m) work(i);    fo(i,1,n)        fd(j,n,i)            v[i][j]=v[i][j]+v[i-1][j]+v[i][j+1]-v[i-1][j+1];    fo(i,1,n)        fo(j,i,n)            ans=max(ans,v[i][j]-(d[j]-d[i]));    printf("%lld\n",ans);}
原创粉丝点击