hdu 4718 The LCIS on the Tree

题意给你q次询问,给一条链问从给定起点到给定终点的最长连续严格递增子序列。

因为给定起点与终点所以路径可能与dfs序的树节点展开顺序相反。所以问题变成了给n个数询问一个区间的最长LCIS。

但因为方向可正可负,所以我们除了维护区间的最长递增以外还要维护最长递减。线段树的部分就做完了。

树链剖分的时候进行线段树合并,合并的时候右区间取前一个区间,左区间取当前区间。要注意从起点出发的链取最长递减,从终点出发的取最长递增。

当他们来到一条链时,当x比y 的深度更浅这时应该将这段长度与y合并,y比x浅时应该将长度与x合并。因为链都是向上合并的,不能向下合并。

最后将起点的最长递减与终点的最长递增比较,如果起点合并后的左端点小于终点合并后的左端点就将起点区间的左长度与终点区间的左长度加起来更新答案。

对拍大法好!!

#include <bits/stdc++.h>
#define Lson l,mid,rt<<1
#define Rson mid+1,r,rt<<1|1
using namespace std;
const int M = 1e5+7;
int _,n,q,a[M];
int head[M],cnt,tot,tmp,cas=1;
int sz[M],f[M],dep[M],son[M],rnk[M],top[M],id[M];
struct edge
{
    int v,next;
}e[M<<1];
struct Tree
{
    int len;
    int lnum,rnum;
    int inl,inr,in;
    int del,der,de;
}tree[M<<3];
void init(){
    cnt=tot=0;memset(head,-1,sizeof(head));
}
void add(int u,int v){
    e[++cnt].v=v;e[cnt].next=head[u];
    head[u]=cnt;
}
void dfs(int u,int fa,int d){
    sz[u]=1;son[u]=-1;f[u]=fa;dep[u]=d;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==fa) continue;
        dfs(v,u,d+1);
        sz[u]+=sz[v];
        if(son[u]==-1||sz[v]>sz[son[u]]) son[u]=v;
    }
    return ;
}
void dfs1(int u,int t){
    id[u]=++tot;
    rnk[tot]=u;
    top[u]=t;
    if(son[u]==-1) return ;
    dfs1(son[u],t);
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==f[u]||v==son[u]) continue;
        dfs1(v,v);
    }
    return ;
}
void Pushup(int rt,int l,int r){
    tree[rt].len=tree[l].len+tree[r].len;
    tree[rt].lnum=tree[l].lnum;
    tree[rt].rnum=tree[r].rnum;
    tree[rt].inl=tree[l].inl;
    tree[rt].inr=tree[r].inr;
    tree[rt].in=max(tree[l].in,tree[r].in);
    tree[rt].del=tree[l].del;
    tree[rt].der=tree[r].der;
    tree[rt].de=max(tree[l].de,tree[r].de);
    if(tree[l].rnum<tree[r].lnum){
        if(tree[l].inl==tree[l].len) tree[rt].inl+=tree[r].inl;
        tree[rt].in=max(tree[rt].in,tree[rt].inl);
        if(tree[r].inr==tree[r].len) tree[rt].inr+=tree[l].inr;
        tree[rt].in=max(tree[rt].in,tree[rt].inr);
        tree[rt].in=max(tree[rt].in,tree[l].inr+tree[r].inl);
    }
    if(tree[l].rnum>tree[r].lnum){
        if(tree[l].del==tree[l].len) tree[rt].del+=tree[r].del;
        tree[rt].de=max(tree[rt].de,tree[rt].del);
        if(tree[r].der==tree[r].len) tree[rt].der+=tree[l].der;
        tree[rt].de=max(tree[rt].de,tree[rt].der);
        tree[rt].de=max(tree[rt].de,tree[l].der+tree[r].del);
    }
}
void build(int l,int r,int rt){
    if(l==r){
        tree[rt].lnum=tree[rt].rnum=a[rnk[l]];tree[rt].len=1;
        tree[rt].inl=tree[rt].inr=tree[rt].del=tree[rt].der=tree[rt].de=tree[rt].in=1;
        return;
    }
    int mid=(l+r)>>1;
    build(Lson);
    build(Rson);
    Pushup(rt,rt<<1,rt<<1|1);
}
int query(int L,int R,int l,int r,int rt){
    if(L==l&&r==R){
        return rt;
    }
    int mid=(l+r)>>1;
    if(L>mid) return query(L,R,Rson);
    else if(R<=mid) return query(L,R,Lson);
    else{
        int ll=query(L,mid,Lson),rr=query(mid+1,R,Rson);
        Pushup(++tmp,ll,rr);
        return tmp;
    }
}
int sum(int x,int y){
    int fx=top[x],fy=top[y];tmp=M<<2;
    int xl,xr=-1,yl,yr=-1;
    while(fx!=fy){
        if(dep[fx]>dep[fy]){
            xl=query(id[fx],id[x],1,n,1);
            if(xr==-1) xr=xl;
            else{
                Pushup(++tmp,xl,xr);xr=tmp;
            }
            x=f[fx],fx=top[x];
        }
        else{
            yl=query(id[fy],id[y],1,n,1);
            //cout<<tree[yl].lnum<<endl;
            if(yr==-1) yr=yl;
            else{
                Pushup(++tmp,yl,yr);yr=tmp;
            }
            y=f[fy],fy=top[y];
        }
        //cout<<fx<<" "<<fy<<" "<<tree[yr].de<<endl;
    }
    if(dep[x]<dep[y]){
        yl=query(id[x],id[y],1,n,1);
        if(yr==-1) yr=yl;
        else{
            Pushup(++tmp,yl,yr);yr=tmp;
        }
    }
    else{
        xl=query(id[y],id[x],1,n,1);
        if(xr==-1) xr=xl;
        else{
            Pushup(++tmp,xl,xr);xr=tmp;
        }
    }
    if(xr==-1) return tree[yr].in;
    if(yr==-1) return tree[xr].de;
    int res;
    //cout<<tree[xr].de<<" "<<tree[yr].in<<endl;
    res=max(tree[xr].de,tree[yr].in);
    if(tree[xr].lnum<tree[yr].lnum){
        res=max(res,tree[xr].del+tree[yr].inl);
    }
    return res;
}
int main(){
    scanf("%d",&_);
    while(_--){
        init();
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=2;i<=n;i++){
            int u;
            scanf("%d",&u);
            add(u,i);add(i,u);
        }
        dfs(1,-1,1);dfs1(1,1);
        build(1,n,1);
        scanf("%d",&q);
        printf("Case #%d:\n",cas++);
        while(q--){
            int from,to;
            scanf("%d%d",&from,&to);
            printf("%d\n",sum(from,to));
        }
        if(_) printf("\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/LMissher/p/9551637.html

时间: 2024-10-15 16:24:54

hdu 4718 The LCIS on the Tree的相关文章

HDU 4718 The LCIS on the Tree(树链剖分)

Problem Description For a sequence S1, S2, ... , SN, and a pair of integers (i, j), if 1 <= i <= j <= N and Si < Si+1 < Si+2 < ... < Sj-1 < Sj , then the sequence Si, Si+1, ... , Sj is a CIS(Continuous Increasing Subsequence). The

H - The LCIS on the Tree HDU - 4718

The LCIS on the Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 1615    Accepted Submission(s): 457 题目链接 https://vjudge.net/problem/UVA-12655 Problem Description For a sequence S1, S2, ...

HDU 4836 The Query on the Tree lca || 欧拉序列 || 动态树

lca的做法还是很明显的,简单粗暴, 不过不是正解,如果树是长链就会跪,直接变成O(n).. 最后跑的也挺快,出题人还是挺阳光的.. 动态树的解法也是听别人说能ac的,估计就是放在splay上剖分一下,做法还是比较复杂的,,, 来一发lca: #include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #inc

hdu 4670 Cube number on a tree(点分治)

Cube number on a tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 1628    Accepted Submission(s): 382 Problem Description The country Tom living in is famous for traveling. Every year, man

HDU 1166 敌兵布阵 Segment Tree题解

本题是最基本的分段树操作了.或者一般叫线段树,不过好像和线段没什么关系,只是分段了. 不使用lazy标志,更新只是更新单点. 如果不使用分段树,那么更新时间效率只需要O(1),使用分段树更新效率就需要O(lgn)了. 但是不是用分段树,那么查询的时间效率是O(n),而分段树查询效率是O(lgn) 这就是amortize分摊了时间,而且lgn真的很快,数据不是非常巨大的时候,接近常数了. 故此本题需要使用分段树. #include <cstdio> class EnemyInfo { stati

HDU 1394 Minimum Inversion Number Segment Tree解法

本题有两个考点: 1 求逆序数的性质 计算逆序数的公式, 一个数arr[i]从前面放到后面,必然会有n-arr[i]-1个数比这个大,那么就有n-arr[i]-1个逆序数增加,同时因为前面少了个arr[i]数,那么就必然有arr[i]个(加上零)数比起小的数失去一个逆序数,总共失去arr[i]个逆序数,所以新的逆序数为增加了n-arr[i]-1-arr[i]个逆序数(当然有可能是减小了,视arr[i]的值而定. 2 如何求一个数列的逆序数 可以使用归并排序来求,也可以使用线段树来求.两者都是二分

HDU4718 The LCIS on the Tree(LCT)

又是一枚LCT,写一发加深一下对LCT的理解.本题的坑爹之处就在于,它实在是太坑爹了.询问的是树路径上的最长连续上升的子串,考验的是怎么样去维护.一开始的想法是维护三个变量 ls,rs,mxl,分别表示左起最长上升,右末最长上升,以及总的最长上升,那么最长上升一定是可以在下面的条件下求到的, mxl=max(ch[0]->mxl,ch[1]->mxl) 以及 令temp=1 存一下左右区间的左右lval,rval, if val>ch[0]->rval temp+=ch[0]-&g

hdu 3999 The order of a Tree

题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=3999 The order of a Tree Description As we know,the shape of a binary search tree is greatly related to the order of keys we insert. To be precisely:1.  insert a key k to a empty tree, then the tree beco

HDU 1710 二叉树的遍历 Binary Tree Traversals

Binary Tree Traversals Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4330    Accepted Submission(s): 1970 Problem Description A binary tree is a finite set of vertices that is either empty or