hihocoder 1232 || 2015北京网络赛F题 树连剖分

http://hihocoder.com/problemset/problem/1232

描述

"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?

输入

The input consists of no more than 8 test cases.

For each test case:

The first line contains two integers, N and M, indicating the number of vertices and the number of queries.(1≤N,M≤100,000)

The next line contains N−1 integers. It describes the structure of wife tree in this way: If the ith integer is k, it means that the vertex labeled k is the father vertex of the vertex labeled (i+1) . It's guaranteed that a vertex X's father vertex can't have a larger label than X does.

The next line describes the husband tree in the same way.

Then next M lines describe the queries. Each line contains two integers Xi and Yi. Let Ki be the earliest possible meeting vertex of the ith query (K0 is defined as 0). In the ith query, Ada's thumb was put at the vertex labeled (Xi+Ki−1) mod N + 1 and Asa's thumb was put at the vertex labeled (Yi+Ki−1) mod N + 1.(1≤Xi,Yi≤N) at the beginning.

输出

For each test case:

Output the answer for each query in a single line. The answer contains three integers: the earliest possible meeting vertex, the number of the vertices Ada will encounter and the number of the vertices Asa will encounter (including the starting vertex and the ending vertex). In particular, if they put their thumb at the same vertex at first, the earliest possible meeting vertex should be the starting vertex.

提示

In the first test case:

The wife tree is like this:

hihocoder 1232 || 2015北京网络赛F题 树连剖分_第1张图片

The husband tree is like this:

hihocoder 1232 || 2015北京网络赛F题 树连剖分_第2张图片

The query is (5)[4], and they may meet at {1,3}, so the earliest one is 3.

In the second test case:

The wife tree is like this:

hihocoder 1232 || 2015北京网络赛F题 树连剖分_第3张图片

The husband tree is like this:

hihocoder 1232 || 2015北京网络赛F题 树连剖分_第4张图片

The first query is (1)[4], the second query is (2)[1], and the last one is (5)[2].

For the first query, they may only meet at 1.

For the second query, they may only meet at 1.

For the third query, they may meet at {1,2}, the earliest one is 2.

样例输入
5 1
1 2 3 3
1 1 3 2
4 3
5 3
1 1 2 2
1 2 2 1
5 3
5 4
3 5
5 3
1 1 2 2
1 2 3 1
1 4
1 1
3 4
样例输出
3 2 2
1 1 3
1 2 1
2 2 1
1 2 2
3 1 1
2 1 2
/**
hihocoder 1232 || 2015北京网络赛F题    树连剖分
题目大意:有一对夫妻树,他们的节点个数都一样,都以1为根节点,并且两个树中所有的父亲节点的编号都比其子孙节点小。
          现在分别给出两个树的结构,下面有m组询问,妻子在妻子树的x点出发,丈夫在丈夫树的y点出发,只要二者所到节点的
          编号一样就算相遇,二者只能望父亲节点走,问每次二者的最早的相遇节点是什么,并且求出二者经过的节点的个数
解题思路:树连剖分后,每次在链上找匹配。每棵树都剖一次,solve里面两个循环,枚举两棵树丛节点到根的链。
          首先题目里面有个性质父节点的编号小于子节点,然后就是枚举看两个链L1, L2是否有重复的点。对于每个点i, 找到i
          分别在两棵树中所在链的根f1, f2把i存在 f1, f2中,理论上来说应该用F[f1][f2].push_back(i),但是这样太大,
          而且不是每对f1, f2都有公共点,就用了map,二分查找。
*/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#include <map>
using namespace std;
const int maxn=100500;

int n,m;
vector<int>vec[2][maxn];
int fa[2][maxn],dep[2][maxn],siz[2][maxn],top[2][maxn],son[2][maxn];
map<pair<int,int>,int>mp;
vector<pair<int,int> >ans;
vector<pair<int,int> >::iterator lv[maxn],rv[maxn];

void init()
{
    for(int i=0;i<=n;i++)
    {
        vec[0][i].clear();
        vec[1][i].clear();
    }
    mp.clear();
    ans.clear();
}

void dfs1(int u,int pre,int flag)
{
    son[flag][u]=0,siz[flag][u]=1;
    dep[flag][u]=dep[flag][pre]+1;
    fa[flag][u]=pre;
    int n=vec[flag][u].size();
    for(int i=0;i<n;i++)
    {
        int v=vec[flag][u][i];
        dfs1(v,u,flag);
        if(siz[flag][son[flag][u]]<siz[flag][v])
        {
            son[flag][u]=v;
        }
        siz[flag][u]+=siz[flag][v];
    }
}

void dfs2(int u,int tp,int flag)
{
    top[flag][u]=tp;
    if(son[flag][u])
    {
        dfs2(son[flag][u],tp,flag);
    }
    int n=vec[flag][u].size();
    for(int i=0;i<n;i++)
    {
        int v=vec[flag][u][i];
        if(v==son[flag][u])continue;
        dfs2(v,v,flag);
    }
}

int solve(int x,int y)///分别枚举x和y的所在链,找深度最大的同号顶点
{
    int fai,faj;
    for(int i=x;i;i=fa[0][fai])
    {
        fai=top[0][i];
        for(int j=y;j;j=fa[1][faj])
        {
            faj=top[1][j];
            if(j<fai)break;
            if(i<faj)continue;
            int t=mp[make_pair(fai,faj)];
            if(t==0)continue;
            if((rv[t]-1)->second<=min(i,j))
                return (rv[t]-1)->second;
            else
            {
                vector<pair<int,int> >::iterator id=upper_bound(lv[t],rv[t],make_pair(t,min(i,j)));
                if(id!=lv[t])return (id-1)->second;
            }
        }
    }
}
int main()
{
     while(~scanf("%d%d",&n,&m))
     {
         init();
         for(int i=1;i<n;i++)///wife tree
         {
             int x;
             scanf("%d",&x);
             vec[0][x].push_back(i+1);
         }
         for(int i=1;i<n;i++)///husband tree
         {
             int x;
             scanf("%d",&x);
             vec[1][x].push_back(i+1);
         }
         for(int i=0;i<2;i++)///分别进行树链剖分
         {
             dep[i][0]=0;
             dfs1(1,0,i);
             dfs2(1,1,i);
         }
         int cnt=0;
         for(int i=1;i<=n;i++)///记录每一个节点在两个树中链的位置
         {
             pair<int,int> tmp=make_pair(top[0][i],top[1][i]);
             if(mp[tmp]==0)mp[tmp]=++cnt;
             ans.push_back(make_pair(mp[tmp],i));
         }
         sort(ans.begin(),ans.end());
         for(int i=1;i<=cnt;i++)
         {
             lv[i]=lower_bound(ans.begin(),ans.end(),make_pair(i,0));
             rv[i]=upper_bound(ans.begin(),ans.end(),make_pair(i,n));
         }
         int pre=0;
         while(m--)
         {
             int x,y;
             scanf("%d%d",&x,&y);
             x=(x+pre)%n+1;
             y=(y+pre)%n+1;
             int ret=solve(x,y);
             int ret1=abs(dep[0][x]-dep[0][ret])+1;
             int ret2=abs(dep[1][y]-dep[1][ret])+1;
             pre=ret;
             printf("%d %d %d\n",ret,ret1,ret2);
         }
     }
     return 0;
}


你可能感兴趣的:(hihocoder 1232 || 2015北京网络赛F题 树连剖分)