BZOJ3999: [TJOI2015]旅游
生活随笔
收集整理的這篇文章主要介紹了
BZOJ3999: [TJOI2015]旅游
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
BZOJ3999: [TJOI2015]旅游
Description
為了提高智商,ZJY準備去往一個新世界去旅游。這個世界的城市布局像一棵樹。每兩座城市之間只有一條路徑可 以互達。每座城市都有一種寶石,有一定的價格。ZJY為了賺取最高利益,她會選擇從A城市買入再轉手賣到B城市 。由于ZJY買寶石時經常賣萌,因而凡是ZJY路過的城市,這座城市的寶石價格會上漲。讓我們來算算ZJY旅游完之 后能夠賺取的最大利潤。(如a城市寶石價格為v,則ZJY出售價格也為v)Input
第一行輸入一個正整數N,表示城市個數。 接下來一行輸入N個正整數表示每座城市寶石的最初價格p,每個寶石的初始價格不超過100。 第三行開始連續輸入N-1行,每行有兩個數字x和y。表示x城市和y城市有一條路徑。城市編號從1開始。 下一行輸入一個整數Q,表示詢問次數。 接下來Q行,每行輸入三個正整數a,b,v,表示ZJY從a旅游到b,城市寶石上漲v。 1≤ N≤50000, 1≤Q ≤50000Output
?對于每次詢問,輸出ZJY可能獲得的最大利潤,如果虧本則輸出0。
Sample Input
31 2 3
1 2
2 3
2
1 2 100
1 3 100
Sample Output
11
題解Here! 額,相信大部分人肯定沒有一遍讀懂題意。。。 本蒟蒻也是看別的巨佬的博客弄懂的。。。 出題人語文水平真差。。。 其實就是求從$x$到$y$的有向路徑上任意兩個點的最大差值。
如果這只是一道線段樹題還是十分簡單的:
對于一個區間,其路徑最大差值為:
$$\max \left( \text{右兒子最大差值,左兒子最大差值,(右兒子MAX-左兒子MIN)或者(左兒子MAX-右兒子MIN)} \right)$$
對于這樣的要返回多權值的問題,線段樹傳遞結構體比較容易。
這是鏈上的情況。
然后我們要求的是樹的情況。
辣就用樹鏈剖分在$O(\log_2n)$的時間內轉換成鏈上的情況就好了嘛。。。
注意到要解決好一個方向怎么把控的問題。
因為我們在樹剖一步一步一步往上爬的時候,從詢問起點往上爬和詢問終點往上爬是不一樣的!
我的處理方式是每次都進行判斷是線段樹左到右還是右到左掃最大差值,之后將每段區間內的$\min$和$\max$記錄下來
即:分別開兩個數組從起點爬的和終點爬的。
之后再將這一大段區間的$\min$和$\max$連接成一條鏈,直接暴力跑一次區間最大差值,得到最大答案就是了。
說得容易真的寫得很惡心啊!!!
附上將近$200$行的代碼:
#include<iostream> #include<algorithm> #include<cstdio> #define LSON rt<<1 #define RSON rt<<1|1 #define MAXSUM(x) b[x].maxn #define MINSUM(x) b[x].minn #define MAXL(x) b[x].maxl #define MAXR(x) b[x].maxr #define SIGN(x) b[x].c #define LSIDE(x) b[x].l #define RSIDE(x) b[x].r #define WIDTH(x) (RSIDE(x)-LSIDE(x)+1) #define MAXN 50010 #define MAX (1LL<<62) using namespace std; int n,m,c=1,d=1; int val[MAXN],head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],id[MAXN],pos[MAXN],top[MAXN]; long long min_x[MAXN],max_x[MAXN],min_y[MAXN],max_y[MAXN]; struct Tree{int next,to; }a[MAXN<<1]; struct Segment_Tree{long long maxn,minn,maxl,maxr,c;int l,r; }b[MAXN<<2]; inline int read(){int date=0,w=1;char c=0;while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}return date*w; } inline long long max(const long long x,const long long y){return x>y?x:y;} inline long long min(const long long x,const long long y){return x<y?x:y;} inline void add(int x,int y){a[c].to=y;a[c].next=head[x];head[x]=c++;a[c].to=x;a[c].next=head[y];head[y]=c++; } void dfs1(int rt){son[rt]=0;size[rt]=1;for(int i=head[rt];i;i=a[i].next){int will=a[i].to;if(!deep[will]){deep[will]=deep[rt]+1;fa[will]=rt;dfs1(will);size[rt]+=size[will];if(size[son[rt]]<size[will])son[rt]=will;}} } void dfs2(int rt,int f){id[rt]=d++;pos[id[rt]]=rt;top[rt]=f;if(son[rt])dfs2(son[rt],f);for(int i=head[rt];i;i=a[i].next){int will=a[i].to;if(will!=fa[rt]&&will!=son[rt])dfs2(will,will);} } inline void pushup(int rt){MAXSUM(rt)=max(MAXSUM(LSON),MAXSUM(RSON));MINSUM(rt)=min(MINSUM(LSON),MINSUM(RSON));MAXL(rt)=max(MAXSUM(RSON)-MINSUM(LSON),max(MAXL(LSON),MAXL(RSON)));MAXR(rt)=max(MAXSUM(LSON)-MINSUM(RSON),max(MAXR(LSON),MAXR(RSON))); } inline void pushdown(int rt){if(!SIGN(rt)||LSIDE(rt)==RSIDE(rt))return;SIGN(LSON)+=SIGN(rt);MAXSUM(LSON)+=SIGN(rt);MINSUM(LSON)+=SIGN(rt);SIGN(RSON)+=SIGN(rt);MAXSUM(RSON)+=SIGN(rt);MINSUM(RSON)+=SIGN(rt);SIGN(rt)=0; } void buildtree(int l,int r,int rt){LSIDE(rt)=l;RSIDE(rt)=r;SIGN(rt)=0;if(l==r){MAXSUM(rt)=MINSUM(rt)=val[pos[l]];MAXL(rt)=MAXR(rt)=0;return;}int mid=l+r>>1;buildtree(l,mid,LSON);buildtree(mid+1,r,RSON);pushup(rt); } void update(int l,int r,long long c,int rt){if(l<=LSIDE(rt)&&RSIDE(rt)<=r){SIGN(rt)+=c;MAXSUM(rt)+=c;MINSUM(rt)+=c;return;}pushdown(rt);int mid=LSIDE(rt)+RSIDE(rt)>>1;if(l<=mid)update(l,r,c,LSON);if(mid<r)update(l,r,c,RSON);pushup(rt); } Segment_Tree query(int l,int r,int c,int rt){if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return b[rt];pushdown(rt);int mid=LSIDE(rt)+RSIDE(rt)>>1;if(r<=mid)return query(l,r,c,LSON);if(mid<l)return query(l,r,c,RSON);Segment_Tree ans,lson,rson;lson=query(l,r,c,LSON);rson=query(l,r,c,RSON);ans.maxn=max(lson.maxn,rson.maxn);ans.minn=min(lson.minn,rson.minn);if(c==1)ans.maxr=max(lson.maxn-rson.minn,max(lson.maxr,rson.maxr));elseans.maxl=max(rson.maxn-lson.minn,max(lson.maxl,rson.maxl));return ans; } void update_path(int x,int y,long long k){while(top[x]!=top[y]){if(deep[top[x]]<deep[top[y]])swap(x,y);update(id[top[x]],id[x],k,1);x=fa[top[x]];}if(deep[x]>deep[y])swap(x,y);update(id[x],id[y],k,1); } void solve(int x,int y){int top_x=0,top_y=0;long long ans=0;Segment_Tree s;while(top[x]!=top[y]){if(deep[top[x]]>deep[top[y]]){s=query(id[top[x]],id[x],1,1);ans=max(ans,s.maxr);top_x++;min_x[top_x]=s.minn;max_x[top_x]=s.maxn;x=fa[top[x]];}else{s=query(id[top[y]],id[y],2,1);ans=max(ans,s.maxl);top_y++;min_y[top_y]=s.minn;max_y[top_y]=s.maxn;y=fa[top[y]];}}if(deep[x]>deep[y]){s=query(id[y],id[x],1,1);ans=max(ans,s.maxr);top_x++;min_x[top_x]=s.minn;max_x[top_x]=s.maxn;}else{s=query(id[x],id[y],2,1);ans=max(ans,s.maxl);top_y++;min_y[top_y]=s.minn;max_y[top_y]=s.maxn;}for(int i=top_y;i>=1;i--){top_x++;min_x[top_x]=min_y[i];max_x[top_x]=max_y[i];}long long maxn=-MAX,minn=MAX;for(int i=1;i<=top_x;i++){ans=max(ans,max_x[i]-minn);minn=min(minn,min_x[i]);}for(int i=top_x;i>=1;i--){ans=max(ans,maxn-min_x[i]);maxn=max(maxn,max_x[i]);}if(ans<0)printf("0\n");else printf("%lld\n",ans); } void work(){int x,y,k;while(m--){x=read();y=read();k=read();solve(x,y);update_path(x,y,k);} } void init(){int x,y;n=read();for(int i=1;i<=n;i++)val[i]=read();for(int i=1;i<n;i++){x=read();y=read();add(x,y);}m=read();deep[1]=1;dfs1(1);dfs2(1,1);buildtree(1,n,1); } int main(){init();work();return 0; }?
轉載于:https://www.cnblogs.com/Yangrui-Blog/p/9562845.html
總結
以上是生活随笔為你收集整理的BZOJ3999: [TJOI2015]旅游的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到抓到小偷并打他是什么意思
- 下一篇: 各种蕴含算法思想的DP - 3