Road

題目

這裏寫圖片描述
數據約定:
對於30%的數據, 1≤N,M≤100
對於60%的數據,1≤N,M≤1000
對於100%的數據,1≤N,M≤50000

題意

就是給你一顆n個點的無根樹,每個點都有一個貨物,都有價格。
然後給你m個詢問,每個詢問問你從x->y的路徑中你有序的選兩個貨物,ai,aj
使得ai-aj最大。注意選的時候一定要有順序。

分析

題目是關於樹的,我們可以發現,從x->y的路徑中一定會經過它們的最近公共祖先。
所以我們可以分類討論,有三種情況:
1.在x->lca(x,y)中完成買和賣
2.在lca(x,y)->y中完成買和賣
3.在x->lca(x,y)中買了,在lca(x,y)->y中賣出
其中第三種情況比較簡單,只需要算出兩個rmq一個最大,一個最小
然後在x->lca(x,y)裏面算出最小值,在lca(x,y)->y裏面算出最大值即可。
但是第一第二種情況我們不能這樣算的原因是我們不能保證它們的先後順序。
難道這樣就是錯的,不行,我們繼續思考。
能不能也用一個rmq數組去統計這一段的先賣後買的答案呢?
我們發現這樣是可以的:
我們設g[i,j]表示第i個節點往上2j 個節點的編號。
f[i,j]表示第i個節點往上2j 個節點中的最小值
q[i,j]表示第i個節點往上2j 個節點中的最大值
u[i,j]表示第i個節點往上2j 個節點中的先買後賣的最大值。
g[i,j]=g[g[i,j-1],j-1];
f[i,j]=min(f[g[i,j-1],j-1],f[i,j-1]);
q[i,j]=max(q[g[i,j-1],j-1],q[i,j-1]);
u[i,j]=max(u[i,j-1],u[g[i,j-1],j-1],f[i,j-1]+q[g[i,j-1,j-1]);
這樣我們就可以從x跳到lca(x,y),和lca(x,y)跳到y的路徑中計算答案。
計算答案:
1.在x->lca(x,y)中完成買和賣:
我們不僅每次取跳上去時u的答案,還要每次記錄前面的最小值,然後和後面的最大值的差作比較
2.在lca(x,y)->y中完成買和賣:同理這裏也是
3.在x->lca(x,y)中買了,在lca(x,y)->y中賣出:這裏就直接取最大值最小值作差即可。

代碼

#include<iostream>
#include<cmath> 
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#define maxlongint 2147483647
using namespace std;
const int N=50005;
int nu,n,b[N*2],las[N],nex[N*2],m,x,y,val[N],g[N][20],f[N][20],q[N][20],u[N][20][2],d[N],fa[N];
void insert(int x,int y){
    b[++nu]=y;nex[nu]=las[x];las[x]=nu;
}
void dfs(int x,int y){
    for(int p=las[x];p;p=nex[p]){
        if (b[p]!=y) {
            d[b[p]]=d[x]+1;
            g[b[p]][0]=x;
            fa[b[p]]=x;
            f[b[p]][0]=min(val[b[p]],val[x]);
            q[b[p]][0]=max(val[b[p]],val[x]);
            u[b[p]][0][1]=max(0,val[b[p]]-val[x]);
            u[b[p]][0][0]=max(0,val[x]-val[b[p]]);
            dfs(b[p],x);
        }
    }
}
int lca(int x,int y){
    if (d[x]<d[y]) swap(x,y);
    int k=trunc(log(d[x]-d[y]+1)/log(2));
    while (k>=0){
        if (d[g[x][k]]>d[y]) x=g[x][k];
        --k;
    }
    if (d[x]!=d[y]) x=g[x][0];
    k=trunc(log(d[x])/log(2));
    while (k>=0){
        if (g[x][k]!=g[y][k]) x=g[x][k],y=g[y][k];
        k--;
    }
    if (x==y) return x;else return g[x][0];
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&val[i]);
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        insert(x,y);
        insert(y,x);
    }
    d[1]=1;
    dfs(1,0);
    for(int j=1;j<=trunc(log(n)/log(2));j++){
        x=x;
       for(int i=1;i<=n;i++){
          g[i][j]=g[g[i][j-1]][j-1];
          f[i][j]=min(f[i][j-1],f[g[i][j-1]][j-1]);
          q[i][j]=max(q[i][j-1],q[g[i][j-1]][j-1]);
          u[i][j][0]=max(u[i][j-1][0],u[g[i][j-1]][j-1][0]);
          u[i][j][1]=max(u[i][j-1][1],u[g[i][j-1]][j-1][1]);
          u[i][j][0]=max(u[i][j][0],q[g[i][j-1]][j-1]-f[i][j-1]);
          u[i][j][1]=max(u[i][j][1],q[i][j-1]-f[g[i][j-1]][j-1]);
        }
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        int z=lca(x,y);
        int X=x,Y=0,An=maxlongint,bn=0,ans=0;
        int k=trunc(log(d[x]-d[z]+1)/log(2));
        bool p=0;
        while (k>=0){
            if (d[g[X][k]]>=d[z]) {
                ans=max(q[X][k]-An,ans);
                if (!p) {Y=k;p=1;}else bn=max(bn,q[X][k]);
                An=min(An,f[X][k]);
                ans=max(ans,u[X][k][0]);X=g[X][k];
            }--k;
        }
        ans=max(ans,bn-f[x][Y]);
        Y=y;
        k=trunc(log(d[Y]-d[z]+1)/log(2)),bn=maxlongint,X=0;
        int Cn=0;
        p=0;
        while (k>=0){
            if (d[g[Y][k]]>=d[z]) {
                ans=max(Cn-f[Y][k],ans);
                if (!p) {X=k;p=1;}else bn=min(bn,f[Y][k]);
                Cn=max(Cn,q[Y][k]);
                ans=max(ans,u[Y][k][1]);Y=g[Y][k];
            }--k;
        }
        ans=max(max(ans,Cn-An),ans);
        if (p) ans=max(ans,q[y][X]-bn);
        printf("%d\n",ans);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章