(中等) Hiho 1232 Couple Trees(15年北京网络赛F题),主席树+树链剖分。

  "Couple Trees" are two trees, a husband tree and a wife tree. They are named because they look like a couple leaning on each other. They share a same root, and their branches are intertwined. In China, many lovers go to the couple trees. Under the trees, lovers wish to be accompanied by a lifetime.

Ada and her boyfriend Asa came to the couple trees as well. They were very interested in the trees. They were all ACMers, so after careful observation, they found out that these two trees could be considered as two "trees" in graph theory. These two trees shared N vertices which were labeled 1 to N, and they all had exactly N vertices. Vertices 1 was the root of both trees.

Ada and Asa wanted to know more about the trees‘ rough bark, so each of them put one thumb at a vertices. Then they moved their thumbs towards the root. Ada moved along the wife tree, and Asa moved along the husband tree. Of course, they could moved at different speed.

At that moment, a thought suddenly came to Ada‘s mind: their thumbs may meet before the root. Which one was the earliest possible meeting vertex? And how many vertices would Ada and Asa encounter on the way to the meeting vertex?

  题意差不多就是对于N个点有两棵树,也就是两棵树边不同但是共用所有点,然后询问两个点,问这两个点分别沿着两颗树向根部走,然后路径的交点中最近的那个。

  相当经典的题目,比赛的时候就是没想出来,结果比赛完了一想到主席树这题就会了。。。

  因为每个点都是向着根部走,所以这里应该自然而然想到主席树才对,因为每一个节点都是在其父亲的基础上加了一个点。

  至于维护什么就想了一段时间了。。。

  因为是两棵树,对第一颗树进行树链剖分,得到每个点剖分之后的位置,然后用主席树维护第二棵树的每个点,维护从根节点到这个点所经过的所有的点的树剖之后的位置。

  然后询问的时候就让那个点在第一颗树上跑,每次询问一个区间,然后一直这样得到第一个位置就是了。。。

代码如下:

// ━━━━━━神兽出没━━━━━━
//      ┏┓       ┏┓
//     ┏┛┻━━━━━━━┛┻┓
//     ┃           ┃
//     ┃     ━     ┃
//     ████━████   ┃
//     ┃           ┃
//     ┃    ┻      ┃
//     ┃           ┃
//     ┗━┓       ┏━┛
//       ┃       ┃
//       ┃       ┃
//       ┃       ┗━━━┓
//       ┃           ┣┓
//       ┃           ┏┛
//       ┗┓┓┏━━━━━┳┓┏┛
//        ┃┫┫     ┃┫┫
//        ┗┻┛     ┗┻┛
//
// ━━━━━━感觉萌萌哒━━━━━━

// Author        : WhyWhy
// Created Time  : 2015年09月21日 星期一 23时30分54秒
// File Name     : F.cpp

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>

using namespace std;

const int MaxN=100005;
const int MaxNode=2200006;

int N;

struct Chair_Tree
{
    int Tcou;
    int TreeRoot[MaxN];
    int lson[MaxNode],rson[MaxNode];
    int BIT[MaxNode];

    void insert(int old,int ne,int id)
    {
        old=TreeRoot[old];

        int newRoot=Tcou++;
        int L=1,R=N,M;

        TreeRoot[ne]=newRoot;
        BIT[newRoot]=max(id,BIT[old]);
        while(R>L)
        {
            M=(L+R)>>1;
            if(id<=M)
            {
                lson[newRoot]=Tcou++;
                rson[newRoot]=rson[old];
                newRoot=lson[newRoot];
                old=lson[old];
                R=M;
            }
            else
            {
                lson[newRoot]=lson[old];
                rson[newRoot]=Tcou++;
                newRoot=rson[newRoot];
                old=rson[old];
                L=M+1;
            }
            BIT[newRoot]=max(id,BIT[old]);
        }
    }

    int query(int ql,int qr,int L,int R,int po)
    {
        if(ql<=L && qr>=R)
            return BIT[po];

        int M=(L+R)>>1;
        int ret=0;

        if(ql<=M) ret=max(ret,query(ql,qr,L,M,lson[po]));
        if(qr>M) ret=max(ret,query(ql,qr,M+1,R,rson[po]));

        return ret;
    }

    int query(int tree,int ql,int qr)
    {
        return query(ql,qr,1,N,TreeRoot[tree]);
    }

    int Build(int L,int R)
    {
        int root=Tcou++;

        BIT[root]=0;
        if(L!=R)
        {
            int M=(L+R)>>1;
            lson[root]=Build(L,M);
            rson[root]=Build(M+1,R);
        }
        return root;
    }

    void init()
    {
        Tcou=0;
        TreeRoot[0]=Build(1,N);
    }
}tree;

int fa1[MaxN],fa2[MaxN];
int dep1[MaxN],dep2[MaxN];

struct Edge
{
    int to,next;
};

Edge E[MaxN*2];
int Ecou,head[MaxN];

int fa[MaxN],dep[MaxN],son[MaxN],siz[MaxN],top[MaxN],w[MaxN],fw[MaxN];
int Tcou;

void init()
{
    Ecou=0;
    Tcou=1;
    w[1]=1;                //!!!
    fw[1]=1;            //!!!
    top[1]=1;            //!!!
    memset(head,-1,sizeof(head));
}

void addEdge(int u,int v)
{
    E[Ecou].to=v;
    E[Ecou].next=head[u];
    head[u]=Ecou++;
}

void dfs1(int u,int pre,int d)
{
    int v;

    dep[u]=d;
    fa[u]=pre;
    siz[u]=1;
    son[u]=-1;

    for(int i=head[u];i!=-1;i=E[i].next)
        if(E[i].to!=pre)
        {
            v=E[i].to;
            dfs1(v,u,d+1);
            siz[u]+=siz[v];

            if(son[u]==-1 || siz[son[u]]<siz[v])
                son[u]=v;
        }
}

void dfs2(int u)
{
    if(son[u]==-1)
        return;

    top[son[u]]=top[u];
    w[son[u]]=++Tcou;
    fw[w[son[u]]]=son[u];

    dfs2(son[u]);

    int v;

    for(int i=head[u];i!=-1;i=E[i].next)
        if(E[i].to!=son[u] && E[i].to!=fa[u])
        {
            v=E[i].to;
            top[v]=v;
            w[v]=++Tcou;
            fw[w[v]]=v;                    // !!!

            dfs2(v);
        }
}

int query(int tr,int u)
{
    int f=top[u];
    int ret;

    while((ret=tree.query(tr,w[f],w[u]))==0)
    {
        u=fa[f];
        f=top[u];
    }

    return fw[ret];
}

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);

    int Q;
    int a,b;
    int t;

    while(~scanf("%d %d",&N,&Q))
    {
        t=0;
        tree.init();
        init();
        fa1[1]=fa2[1]=0;
        dep1[1]=dep2[1]=0;

        for(int i=2;i<=N;++i)
        {
            scanf("%d",&a);
            addEdge(a,i);
            addEdge(i,a);
            dep1[i]=dep1[a]+1;
        }
        dfs1(1,-1,1);
        dfs2(1);

        tree.insert(0,1,1);
        for(int i=2;i<=N;++i)
        {
            scanf("%d",&a);
            dep2[i]=dep2[a]+1;
            tree.insert(a,i,w[i]);
        }

        while(Q--)
        {
            scanf("%d %d",&a,&b);
            a=(a+t)%N+1;
            b=(b+t)%N+1;
            t=query(b,a);
            printf("%d %d %d\n",t,dep1[a]-dep1[t]+1,dep2[b]-dep2[t]+1);
        }
    }

    return 0;
}

时间: 2025-01-15 05:54:03

(中等) Hiho 1232 Couple Trees(15年北京网络赛F题),主席树+树链剖分。的相关文章

hihoCoder #1388 : Periodic Signal ( 2016 acm 北京网络赛 F题)

时间限制:5000ms 单点时限:5000ms 内存限制:256MB 描述 Profess X is an expert in signal processing. He has a device which can send a particular 1 second signal repeatedly. The signal is A0 ... An-1 under n Hz sampling. One day, the device fell on the ground accidenta

2015北京网络赛A题The Cats&#39; Feeding Spots

题意:给你一百个点,找个以这些点为中心的最小的圆,使得这个圆恰好包含了n个点,而且这个圆的边界上并没有点 解题思路:暴力枚举每个点,求出每个点到其他点的距离,取第n大的点,判断一下. 1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<iostream> 5 #include<memory.h> 6 using namespace std; 7 const i

Hiho 1232 北京网络赛 F Couple Trees

给两颗标号从1...n的树,保证标号小的点一定在上面.每次询问A树上的x点,和B树上的y点同时向上走,最近的相遇点和x,y到这个点的距离. 比赛的时候想用倍增LCA做,但写渣了....后来看到题解是主席树就写了一发 呆马: 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 #inclu

2015北京网络赛 F Couple Trees 暴力倍增

Couple Trees Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://hihocoder.com/problemset/problem/1232 Description "Couple Trees" are two trees, a husband tree and a wife tree. They are named because they look like a couple leaning on each other.

acm 2015北京网络赛 F Couple Trees 主席树+树链剖分

提交 题意:给了两棵树,他们的跟都是1,然后询问,u,v 表 示在第一棵树上在u点往根节点走 , 第二棵树在v点往根节点走,然后求他们能到达的最早的那个共同的点 解: 我们将第一棵树进行书链剖,然后第二棵树采用主席树,他的信息来自他的父亲节点,每个点存他在第一棵树 树链剖分后的位置,这样我们每次查询uv的时候我们只要 我们选取u和top[u]这段区间在主席树v这颗树上找,在这个区间能取到的最大值,一旦存在,这个最大值就我们要的,这个点保存着他到根节点这条路上所有点在第一棵树剖分后的位置 #inc

hihocoder 1236(2015北京网络赛 J题) 分块bitset乱搞题

题目大意: 每个人有五门课成绩,初始给定一部分学生的成绩,然后每次询问给出一个学生的成绩,希望知道在给定的一堆学生的成绩比这个学生每门都低或者相等的人数 因为强行要求在线查询,所以题目要求,每次当前给定的学生成绩都异或上一次的答案 先将学生按每一门成绩都排一次序 这里将学生分块成sqrt(n)的块数,然后在当前块中用bitset容器来记录含有学生的状态 这里可以记录状态的前缀和,因为比后面成绩好的,必然比前面的学生的成绩也好 查询的时候只要查到正好比他高的学生属于哪一块,这样只要访问sqrt(n

HDU 5033 Building(北京网络赛B题) 单调栈 找规律

做了三天,,,终于a了... 11724203 2014-09-25 09:37:44 Accepted 5033 781MS 7400K 4751 B G++ czy Building Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 1257    Accepted Submission(s): 358 Special Judg

HDU 5040 Instrusive(北京网络赛I题)

HDU 5040 Instrusive 题目链接 思路:记忆化广搜,先预处理出图,每个位置用一个二进制数表示,表示4秒为1个周期内,这个位置是否会被照到,然后进行记忆化广搜即可,状态多开一个4,表示在4秒一周期,然后进行转移即可 代码: #include <cstdio> #include <cstring> #include <queue> using namespace std; const int N = 505; const int d[4][2] = {-1,

HDU 5037 FROG 贪心 2014北京网络赛F

题目链接:点击打开链接 题意:有一条小河长为M的小河,可以看作一维轴,小河里存在N个石头,有一个每次能跳L米的小青蛙,随意添加石头保证青蛙能从头跳到尾的,问青蛙使用最优策略跳到对岸最多需要多少次. 思路:不妨假设青蛙每个石头都要经过一次,用step表示青蛙上一次跳的步长,每跳一次对目前点到下一点的距离和step的和与L做比较,如果小与,证明青蛙可以一次跳到这,更新step和青蛙位置,cnt保持不变,若大于,证明青蛙至少需要再跳一次,若lenth<=l,则直接跳,更新step=lenth,cnt+