关闭

动态树 解题报告

标签: 倍增
548人阅读 评论(0) 收藏 举报
分类:

这个题我做的时候没有考虑到一个性质,导致多了一个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]);    
        }
    }
}
0
0
查看评论

动态树LCT总结

动态树中最关键的一个函数就是Access(
  • gmcather
  • gmcather
  • 2014-08-20 17:06
  • 857

【动态树】【Link Cut Tree】动态树的理解(入门)

引入现在我们需要一个数据结构满足支持以下的操作: 两个节点连接(保证不出现环) 两个节点断开 求任意两个节点之间的区间和 这样是不是很像树链剖分? 但是因为是动态的所以我们采用动态树来进行维护。样例现在给出一个样例,我们一下的解释都以当前样例为模板 我们有三个节点1 2 3 4,现在他们是连接在一...
  • JeremyGJY
  • JeremyGJY
  • 2016-04-07 17:50
  • 5206

BZOJ 2759 一个动态树好题 Link-Cut-Tree+扩展欧几里得

题目大意:给定n个形如xi=ki*x_pi+bi mod p的同余方程组 支持修改操作和求解操作 确实好题 感谢此题作者 顺便吐槽一下作者的Splay不加空节点太蛋疼了0.0 将每个点i的父亲设为pi 我们将会得到一座基环树林 将环上的一条边拆掉,在边的起始节点新开个域special_fathe...
  • PoPoQQQ
  • PoPoQQQ
  • 2014-10-24 22:57
  • 2355

【HDU】5002 Tree 动态树模板题

传送门:【HDU】5002 Tree
  • u013368721
  • u013368721
  • 2014-09-28 16:33
  • 738

bzoj2759:一个动态树好题 (LCT+Exgcd)

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2759 题目分析:这是一道真动态树好题,不像某些其它自称好题的题目(bzoj4300“绝世好题”,其实是大水题)。 言归正传,我们来看看这道题。如果有一条方程是a=ka+b%10007的...
  • KsCla
  • KsCla
  • 2017-06-06 13:26
  • 357

动态树LCT 模板

题目描述: 输入: 第一行两个整数n和m; 接下来一行中n个整数表示初始点权; 接下来m行每行一个操作如上表所示。输出: 对于每一个连接操作,若p和q不连通,输出YES,并添加这条边;否则输出NO; 对于每一个删除操作...
  • Todobe
  • Todobe
  • 2017-04-04 15:28
  • 303

动态树问题

前言当一类题目中的树需要支持换根、加边、删边的这些操作时,会改变树的形态,并要求维护一些信息,这类问题称为动态树问题。link cut tree这里有我写的学习小记 link cut tree学习小记 支持的功能:换根,加边,删边,链上信息维护。 不支持的功能:子树信息维护。 习题:弹飞绵羊...
  • WerKeyTom_FTD
  • WerKeyTom_FTD
  • 2016-05-09 20:40
  • 707

BZOJ 3589 动态树 树链剖分+容斥原理

题目大意:给定一棵以1为根的有根树,每个节点有点权,提供两种操作: 1.以某个节点为根的子树所有节点权值+x 2.求一些链的并集的点权和,其中这些链都是由某个节点出发指向根 首先子树修改,链上查询,树链剖分的WT~ 然后这些链上的每个点的点权都只能被加一次,肯定不能打标记,由于k 总权值=...
  • PoPoQQQ
  • PoPoQQQ
  • 2014-10-23 12:51
  • 2255

从《NOI2014 魔法森林》看动态树(LCT)的简单应用

题目大意 给定一个n个结点,m条边的的无向图,每条边有两个权值ai,bi。 现在从1出发,要到达n,出发时带上任意多的A,B,每次只能沿着ai≤A且bi≤B的边走,问至少要带多少的A,B使得能从1到n。 Data Constraint n≤50000,m≤200000
  • Akak__ii
  • Akak__ii
  • 2017-01-01 23:31
  • 754

lct动态树

听fks一席言语,苦读几时汉书 观szb一顿操作,白玩十年反恐 其实在学lct前的话,一定是要学习树剖的,但是我树剖的那个博客还没写,我就来写lct; 为什么; 其实树剖好理解,但是lct我吃了少亏; 多亏上面的两位大佬慷慨相助,我才有所小悟;lct对于树剖来说,就是更动态; 比如换根...
  • largecub233
  • largecub233
  • 2017-05-19 22:23
  • 196
    个人资料
    • 访问:175518次
    • 积分:3642
    • 等级:
    • 排名:第10673名
    • 原创:187篇
    • 转载:1篇
    • 译文:0篇
    • 评论:25条
    最新评论