【GDKOI2015】V

【GDKOI2015】V

Description
给定一颗 n 个节点, 编号依次为 1 到 n 的树。 要求依次回答 q 个询问, 每次询问u到v节点的最短路经过的点序列u>...>v中,连续子序列 a1,a2 … ak 满足a1<a2<a3...<aj>aj+1>aj+2>.....>ak或者a1>a2>a3...>aj<aj+1<aj+2<....<ak1<=j<=k,求最大的 k。

Input
第一行有一个整数 N 表示点个数。
第二行 N-1 个数,第 i 个数表示 i+1 号节点的父亲。 1 号节点总是为根。
第三行一个整数 Q,表示询问个数。
接下来有 Q 行, 每行两个整数 u,v。 (每次输入的 u 和 v 需要异或上次询问的结果,得到真正的询问的 u、 v 节点,第一个询问异或 0)

Output
每个询问输出一行,一个整数

Sample

Input1:
1
2
1 1
0 0
Output1:
1
1
Input2:
2
1
2
1 1
0 3
Output2:
1
2

Data Constraint
对于 20%数据, N,Q≤100
对于 40%数据, N,Q≤20000
对于 70%数据, N,Q≤50000
对于 100%数据, N,Q≤100000


analysis

很容易可以想到LCT
抽出一条链直接输出
至于维护,只需要存几个东东
左端向上,右端向上,左端向下,右端向下,左端向上在向下,左端向下再向上,右端向上在向下,右端向下再向上,答案,长度,也不多
O(nlogn)可以过?
常数为7*10,开心地T了
其实只用减掉LCT的常数,也就是用一种常数为1*10的方法即可
倍增

注意细节。。。

code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100100
using namespace std;

int n,m,deep[N];
struct data{
    int x,l,r,lu,ru,ld,rd,lup,rup,ldo,rdo,len,mx;
    void clear(){
        len=x=l=r=lu=ru=ld=rd=lup=rup=ldo=rdo=mx=0;
    }
    void init(int w,int fa){
        mx=len=lu=ld=ru=rd=lup=rup=ldo=rdo=1;l=r=w;x=fa;
    }
}f[18][N],ans;

void merge(data a,data b,data &c){
    if(!a.len){
        c=b;return;
    }
    if(!b.len){
        c=a;return;
    }
    c.x=b.x;c.len=a.len+b.len;c.l=a.l;c.r=b.r;c.mx=max(a.mx,b.mx);
    c.lup=a.lup;c.lu=a.lu;c.ldo=a.ldo;c.ld=a.ld;
    c.rup=b.rup;c.ru=b.ru;c.rdo=b.rdo;c.rd=b.rd;
    if(a.r>b.l){
        c.mx=max(c.mx,max(a.rdo+b.ld,a.rd+b.ldo));
        if(a.rdo==a.len)c.lup=a.rdo+b.ld;if(a.rd==a.len)c.ldo=a.rd+b.ldo,c.ld=a.rd+b.ld;
        if(b.ldo==b.len)c.rup=b.ldo+a.rd;if(b.ld==b.len)c.rdo=b.ld+a.rdo,c.rd=a.rd+b.ld;
    }
    if(a.r<b.l){
        c.mx=max(c.mx,max(a.rup+b.lu,a.ru+b.lup));
        if(a.rup==a.len)c.ldo=a.rup+b.lu;if(a.ru==a.len)c.lup=a.ru+b.lup,c.lu=a.ru+b.lu;
        if(b.lup==b.len)c.rdo=b.lup+a.ru;if(b.lu==b.len)c.rup=b.lu+a.rup,c.ru=a.ru+b.lu;
    }
}

int getdep(int x){
    int ans=0;
    for(int i=17;i+1;i--)if(f[i][x].x)ans+=f[i][x].len,x=f[i][x].x;
    return ans+1;
}
data lca(int x,int y){
    if(deep[x]>deep[y])return lca(y,x);
    data a,b;a.clear();b.clear();
    for(int i=17;i+1;i--)if(deep[x]<=deep[f[i][y].x])merge(b,f[i][y],b),y=f[i][y].x;
    if(x==y){merge(b,f[0][x],b);return b;}
    for(int i=17;i+1;--i)
        if(f[i][x].x!=f[i][y].x)merge(a,f[i][x],a),merge(b,f[i][y],b),x=f[i][x].x,y=f[i][y].x;
    swap(b.l,b.r);swap(b.lu,b.rd);swap(b.ld,b.ru);swap(b.lup,b.rdo);swap(b.ldo,b.rup);
    merge(a,f[0][x],a);x=f[0][x].x;merge(f[0][y],b,b);merge(a,f[0][x],a);merge(a,b,b);return b;
}

int main(){
    scanf("%d",&n);f[0][1].init(1,0);
    for(int i=1;i<n;i++){
        int x;scanf("%d",&x);f[0][i+1].init(i+1,x);
    }
    for(int i=0;i<18;i++)f[i][0].clear();
    for(int j=1;j<18;j++)for(int i=1;i<=n;i++)
        if(f[j-1][f[j-1][i].x].x)merge(f[j-1][i],f[j-1][f[j-1][i].x],f[j][i]);else f[j][i].clear();
    for(int i=1;i<=n;i++)deep[i]=getdep(i);
    scanf("%d",&m);
    for(int i=1,las=0;i<=m;i++){
        int x,y;scanf("%d %d",&x,&y);x^=las;y^=las;
        ans=lca(x,y);las=ans.mx;printf("%d\n",las);
    }
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/white_elephant/article/details/80321112
个人分类: 倍增
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

【GDKOI2015】V

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭