动态树 解题报告

这个题我做的时候没有考虑到一个性质,导致多了一个log,然后麻烦了好多好多。
就是说合并两个区间的时候,我以为左边的最小值会接管右边第一个比它小的左边的一段,所以我要求这一段的最大值。
但是实际上,如果右边右段的最大值比右边左段的最大值大的话,显然这是无论如何都不能更新答案的,所以我们直接用右边的最大值就好了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#include<algorithm>
#include<cstdlib>
#define inf 1e9
//About read
inline void in(int &x){
    char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    x=0;
    for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
}
int a[200005];
//About tree
int ptr[100005],next[200005],succ[200005],etot=1;
int fa[200005][18],son[200005][18];//[i,i+2^j)
int depth[200005];
struct TS{
    int max,min,ans,revans;
}st[200005][18];
inline void addedge(int u,int v){
    next[etot]=ptr[u],ptr[u]=etot,succ[etot++]=v;
}
inline TS merge(TS a,TS b){
    return (TS){max(a.max,b.max),min(a.min,b.min),max(b.max-a.min,max(a.ans,b.ans)),max(a.max-b.min,max(a.revans,b.revans))};
}
inline void out(TS a){
    cout<<"{"<<a.max<<","<<a.min<<","<<a.ans<<","<<a.revans<<"}";
}
inline void build(int node){
    depth[node]=depth[fa[node][1]]+1;

    fa[node][0]=node;
    for(int i=2;i<18;++i)fa[node][i]=fa[fa[node][i-1]][i-1];

    st[node][0]=(TS){a[node],a[node],0};
    st[node][1]=(TS){max(a[fa[node][1]],a[node]),min(a[fa[node][1]],a[node]),max(a[fa[node][1]]-a[node],0),max(a[node]-a[fa[node][1]],0)};
    for(int i=2;i<18;++i){
        st[node][i]=merge(st[node][i-1],st[fa[node][i-1]][i-1]);
        /*cout<<"Merge:";
        out(st[node][i-1]);
        cout<<"+";
        out(st[fa[node][i-1]][i-1]);
        cout<<"=";
        out(st[node][i]);
        cout<<endl;*/
    }

    for(int i=ptr[node];i;i=next[i])
        if(succ[i]!=fa[node][1]){
            fa[succ[i]][1]=node;
            build(succ[i]);
        }
}
int main(){
    freopen("lct.in","r",stdin);
    freopen("lct.out","w",stdout);
    int n,m,i,j,u,v,s,t,type;
    in(n);
    for(i=1;i<=n;++i)in(a[i]);
    for(i=n;--i;){
        in(u),in(v);
        addedge(u,v),addedge(v,u);
    }
    build(1);
    /*for(i=1;i<=n;++i){
        cout<<"----"<<i<<"-----\n";
        for(j=0;j<18&&fa[i][j];++j){
            cout<<fa[i][j]<<":";
            out(st[i][j]);
            cout<<endl;
        }
    }*/
    in(m);
    int lastans=0,cha;
    TS ans,revans;
    while(m--){
        in(type);
        if(type==1){
            in(s),in(t);
            s^=lastans,t^=lastans;
            revans=st[t][0],ans=st[s][0],cha=abs(depth[s]-depth[t]);
            if(depth[s]>depth[t])//把s往上调 
                for(i=18;--i;)
                    if(depth[fa[s][i]]>=depth[t]){
                        ans=merge(ans,st[s][i]);
                        s=fa[s][i];
                    }
            if(depth[s]<depth[t])//把t往上调 
                for(i=18;--i;)
                    if(depth[fa[t][i]]>=depth[s]){
                        revans=merge(revans,st[t][i]);
                        t=fa[t][i];
                    }
            if(s!=t){
                for(i=18;--i;)
                    if(fa[s][i]!=fa[t][i]){
                        ans=merge(ans,st[s][i]),revans=merge(revans,st[t][i]);
                        s=fa[s][i],t=fa[t][i];
                    }
                ans=merge(ans,st[s][1]);
            }
            lastans=max(revans.max-ans.min,max(ans.ans,revans.revans));
            printf("%d\n",lastans);
        }
        else{
            in(a[++n]),in(fa[n][1]);
            fa[n][1]^=lastans;
            fa[n][0]=n;
            depth[n]=depth[fa[n][1]]+1;
            for(i=2;i<18;++i)fa[n][i]=fa[fa[n][i-1]][i-1];
            st[n][0]=(TS){a[n],a[n],0};
            st[n][1]=(TS){max(a[n],a[fa[n][1]]),min(a[n],a[fa[n][1]]),max(a[fa[n][1]]-a[n],0),max(a[n]-a[fa[n][1]],0)};
            for(i=2;i<18;++i)st[n][i]=merge(st[n][i-1],st[fa[n][i-1]][i-1]);    
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值