1. 程式人生 > >dtoj#4212. 小X愛旅行(travel)

dtoj#4212. 小X愛旅行(travel)

else 也會 找到 closed spa opened include 一行 景區

題目描述:

OIVillage 是一個風景秀美的鄉村,為了更好的利用當地的旅遊資源,吸引遊客,推動經濟發展,xkszltl 決定修建了一條鐵路將當地 $n$ 個最著名的經典連接起來,讓遊客可以通過火車從鐵路起點( $1$ 號景點)出發,依次遊覽每個景區。為了更好的評價這條鐵路,xkszltl 為每一個景區都賦予了一個美觀度,而一條旅行路徑的價值就是它所經過的景區的美觀度之和。不過,隨著天氣與季節的變化,某些景點的美觀度也會發生變化。

xkszltl 希望為每位旅客提供最佳的旅行指導,但是由於遊客的時間有限,不一定能遊覽全部景區,然而他們也不希望旅途過於短暫,所以每個遊客都希望能在某一個區間內的車站結束旅程,而 xkszltl 的任務就是為他們選擇一個終點使得旅行線路的價值最大。可是當地的景點與前來觀光的旅客實在是太多了,xkszltl 無法及時完成任務,於是找到了準備虐殺 NOI2019 的你,希望你能幫助他完成這個艱巨的任務。

輸入:

第一行給出一個整數 $n$,接下來一行給出 $n$ 的景區的初始美觀度。

第三行給出一個整數 $m$,接下來 $m$ 行每行為一條指令:

$1.~~~0~x~y~k$:表示將 $x$ 到 $y$ 這段鐵路邊上的景區的美觀度加上 $k$;

$2.~~~1~x~y$:表示有一名旅客想要在 $x$ 到 $y$ 這段(含 $x$ 與 $y$ )中的某一站下車,你需要告訴他最大的旅行價值。

數據範圍:

對於 $20\%$ 的數據,$n,m≤3000$;

對於 $40\%$ 的數據,$n,m≤30000$;

對於 $50\%$ 的數據,$n,m≤50000$;

另外 $20\%$ 的數據,$n,m≤100000$,修改操作 $≤20$;

對於 $100\%$ 的數據,$n,m≤100000$。

算法標簽:分塊,凸包

思路:

考慮分塊計算,對於每一個塊做一個凸包,對於單詞修改或詢問如果遍布整個塊,就對這個塊記錄一個 $k,b$ 表示整個塊的數都要進行的操作。

因為是一次函數所以更改後最優答案一定在凸包上。

對於只修改或查詢一個塊內一部分點的情況,暴力操作。

以下代碼:

技術分享圖片
#include<bits/stdc++.h>
#define il inline
#define db double
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using
namespace std; const int N=1e5+5,M=1505; const LL inf=1e18; vector<int> v[M]; int n,m,sz,gr[N],sta[N],top; LL sum[N],k[N],b[N]; il int read(){ int x,f=1;char ch; _(!)ch==-?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il db getk(int x,int y){ return (db)(sum[x]-sum[y])/(db)(x-y); } il void build(int x){ int l=(x-1)*sz+1,r=min(x*sz,n); sta[top=1]=l; for(int i=l+1;i<=r;i++){ while(top>1&&getk(sta[top],sta[top-1])<getk(sta[top-1],i))top--; sta[++top]=i; } v[x].resize(top+1); for(int i=1;i<=top;i++)v[x][i]=sta[i]; } il LL cal(int x){ return sum[x]+k[gr[x]]*x+b[gr[x]]; } il LL query(int x){ int l=1,r=v[x].size()-1; if(l>r)return cal(v[x][1]); while(l<r){ int mid=(l+r)>>1; if(cal(v[x][mid])<cal(v[x][mid+1]))l=mid+1; else r=mid; } return cal(v[x][l]); } il void update(int x){ int l=(x-1)*sz+1,r=min(x*sz,n); LL v=k[x]*l+b[x]; for(int i=l;i<=r;i++)sum[i]+=v,v+=k[x]; k[x]=b[x]=0; } int main() { n=read();sz=sqrt(n/3); for(int i=1;i<=n;i++)sum[i]=sum[i-1]+read(); for(int i=1;i<=n;i++)gr[i]=(i-1)/sz+1; for(int i=1;i<=gr[n];i++)build(i); m=read(); while(m--){ int op=read(),x=read(),y=read(); if(op){ LL ans=-inf; if(gr[x]^gr[y]){ for(int i=x;i<=gr[x]*sz;i++)ans=max(ans,cal(i)); for(int i=(gr[y]-1)*sz+1;i<=y;i++)ans=max(ans,cal(i)); for(int i=gr[x]+1;i<gr[y];i++)ans=max(ans,query(i)); } else{ for(int i=x;i<=y;i++)ans=max(ans,cal(i)); } printf("%lld\n",ans); } else{ int c=read(); if(gr[x]^gr[y]){ LL val=0; for(int i=x;i<=gr[x]*sz;i++)val+=c,sum[i]+=val; val=1ll*((gr[y]-1)*sz-x+1)*c; for(int i=(gr[y]-1)*sz+1;i<=y;i++)val+=c,sum[i]+=val; for(int i=y+1;i<=min(gr[y]*sz,n);i++)sum[i]+=val; for(int i=gr[y]+1;i<=gr[n];i++)b[i]+=val; update(gr[x]);update(gr[y]);build(gr[x]);build(gr[y]); val=-1ll*c*(x-1); for(int i=gr[x]+1;i<gr[y];i++)k[i]+=c,b[i]+=val; } else{ LL val=0; for(int i=x;i<=y;i++)val+=c,sum[i]+=val; for(int i=y+1;i<=min(gr[y]*sz,n);i++)sum[i]+=val; for(int i=gr[y]+1;i<=gr[n];i++)b[i]+=val; update(gr[x]);build(gr[x]); } } } return 0; }
View Code

dtoj#4212. 小X愛旅行(travel)