【codvs3304 3305 3306】水果姐逛水果街系列【線段樹】【樹鏈剖分】

這三道題一個類型的……
第一道題是有一排商店,可以買水果也可以賣水果,買水果和賣水果的價錢一樣。
問你從商店x走到商店y,買賣所得最大收益是多少。
我們可以發現樸素的辦法是一路掃過去,記錄當前最小值,然後更新收益。
這樣應該會T(我沒試過)
這樣丟失了很多信息。
我們考慮一下能不能存起來。
發現解滿足區間加法。
即【L,R】中最大的收益要麼是【L,K】中的收益,要麼是【K,R】中的收益(端點重合不影響),要麼是【K,R】中的最大值減去【L,K】中的最小值。這是針對從左往右走的。
於是乎我們可以用線段樹來維護這些信息。
因爲我們有可能從左往右走,也可能從右往左走,所以記個f數組,f[0]表示從線段樹中下標小的向下標大的走所得的最大收益。
合併就是

zkw::node U(const zkw::node &x,const zkw::node &y){
    return (zkw::node){
        {max(max(x.f[0],y.f[0]),y.max-x.min),
         max(max(x.f[1],y.f[1]),x.max-y.min)},
         max(x.max,y.max),
         min(x.min,y.min)
        };
}

而水果姐逛水果街2、3是一個類型,且2是3的子集。
所以我們只討論3.
樹鏈剖分一下就行了。
關於樹鏈剖分的基礎知識請看這裏
但是注意一點,這裏維護的是點權。
要是查詢的兩個點一開始就相鄰,那麼我們要把答案和最後這兩個點相遇的那個點上的信息合併一下(要不然你粘貼一下樣例會驚喜的發現輸出了不該輸出的0)。
因爲重鏈上從上到下在線段樹中的下標是遞增的,所以當把x朝上提的時候,要把tmp的f[0]和f[1]交換一下,達到“從x向上走”的效果。
最後如果x在y的下面,則還需要翻轉一下f[0],f[1]。詳見代碼。
PS:一開始的時候爆棧了,因爲我一行讀了3個數,跟spoj375搞混了- -
後來我把水果姐2的代碼改了一下交3的時候WA了,原來是光改了線段樹沒改a數組,就70了- -。
ZKW線段樹真是快啊!

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=1<<19|1;
const int mm=200001;
int a[200001];
const int inf=1e8+1;
typedef int arr[mm];
typedef int arr1[mm<<1];
arr1 next,to;
arr list,fa,size,top,son,idx,dep;
int n,m,z,tot;
struct zkw{
    int M;
    struct node{int f[2],max,min;}t[maxn];
    void change(int,int);
    node query(int,int);
}t;
inline zkw::node U(const zkw::node &x,const zkw::node &y){
    return (zkw::node){
        {max(max(x.f[0],y.f[0]),y.max-x.min),
         max(max(x.f[1],y.f[1]),x.max-y.min)},
         max(x.max,y.max),
         min(x.min,y.min)
        };
}
void zkw::change(int x,int v){
    x+=M;
    t[x].max=v;
    t[x].min=v;
    t[x].f[0]=t[x].f[1]=0;
    for(x>>=1;x;x>>=1) t[x]=U(t[x<<1],t[x<<1|1]);
}
zkw::node zkw::query(int l,int r){
        zkw::node lans={{0},-inf,inf},rans={{0},-inf,inf};
        if(l>r) return lans;
        for(l+=M-1,r+=M+1;r^l^1;l>>=1,r>>=1){
            if(~l&1) lans=U(lans,t[l^1]);
            if( r&1) rans=U(t[r^1],rans);
        }
        return U(lans,rans);
    }
inline int read(){
    int x=0;
    char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=x*10+ch-48,ch=getchar();
    return x;
}
void dfs1(int x){
    size[x]=1;son[x]=0;
    for(int k=list[x];k;k=next[k]){
        if(to[k]==fa[x]) continue;
        fa[to[k]]=x;
        dep[to[k]]=dep[x]+1;
        dfs1(to[k]);
        if(size[to[k]]>size[son[x]]) son[x]=to[k];
        size[x]+=size[to[k]];
    }
}
void dfs2(int x,int tp){
    top[x]=tp;
    idx[x]=++z;
    if(son[x]) dfs2(son[x],top[x]);
    for(int k=list[x];k;k=next[k])
        if(to[k]!=fa[x]&&to[k]!=son[x])
            dfs2(to[k],to[k]);
}
inline void add(int a,int b){
    tot++;
    next[tot]=list[a];
    list[a]=tot;
    to[tot]=b;
}
int find(int x,int y){
    zkw::node ans[2]={(zkw::node){0,0,-inf,inf},(zkw::node){0,0,-inf,inf}},tmp;
    int tpx=top[x],tpy=top[y];
    while(tpx!=tpy){
        if(dep[tpx]>dep[tpy]){//cout<<"a\n";
            tmp=t.query(idx[tpx],idx[x]);
            swap(tmp.f[0],tmp.f[1]);
//          cout<<tpx<<" "<<x<<"\n";
            ans[0]=U(ans[0],tmp);
            x=fa[tpx];
//          ans[0]=U(ans[0],(zkw::node){{0,0},a[x],a[x]});
            tpx=top[x];
        }else{//cout<<"b\n";
            tmp=t.query(idx[tpy],idx[y]);
            ans[1]=U(tmp,ans[1]);
            y=fa[tpy];
            ans[1]=U((zkw::node){{0,0},a[y],a[y]},ans[1]);
            tpy=top[y];
        }
//      cout<<"geg";
    }
    if(x==y){ return U(ans[0],U((zkw::node){{0,0},a[x],a[x]},ans[1])).f[0];}
    if(dep[x]>dep[y]){
        tmp=t.query(idx[y],idx[x]);
        swap(tmp.f[0],tmp.f[1]);
        return U(U(ans[0],tmp),ans[1]).f[0];
    }
    else return U(U(ans[0],t.query(idx[x],idx[y])),ans[1]).f[0];
}
int d[mm][2];
void init(){
    n=read();
    t.M=1;
    int opt,x,y;
    while(t.M<n) t.M<<=1;
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<n;++i){
        d[i][0]=read();d[i][1]=read();//讀入!!!!!!
//      printf("%d %d>\n",d[i][0],d[i][1]);
        add(d[i][0],d[i][1]);
        add(d[i][1],d[i][0]);
    }
    dfs1(1);dfs2(1,1);
    for(int i=1;i<=n;++i){
        t.change(idx[i],a[i]);
    }
    m=read();
    while(m--){
        opt=read();
        x=read();y=read();
        if(opt==1)printf("%d\n",find(x,y));
        else a[x]=y,t.change(idx[x],y);
    }
}
int main(){
    init();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章