acm 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. 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?
Input
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.
Output
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.
Sample Input
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
Sample Output
3 2 2
1 1 3
1 2 1
2 2 1
1 2 2
3 1 1
2 1 2
HINT
题意
给你两棵树,都同时往上爬,问你这两个人都能够经过的点中,最大的点是什么,并且都各走了多少步。
注意父节点的编号一定比子节点小。
题解:
本来是想做做倍增的题,然后不小心搜到了这道。想了好久还是不会,看了题解才明白,原来倍增是在优化暴力,但是竟然比正解快!
1.那我们先来讲讲倍增的具体做法吧。
先想想最暴力的方法:就是每次找编号较大的一个的点往上爬,爬到超过另一个点,再换这个点重复这个操作。不难证明如果他们在中途相遇就是我们要找的答案。
但是一个一个往上爬是不是太慢了,确实,那我们就用倍增加速即可。
2.我们怎么能满足于此呢,正解其实是树链剖分+主席树
我一开始看题解也是很懵逼,看了好多遍,都没看懂,于是直接看代码,终于明白题解的意思了,真是太神奇了。
我先讲讲具体做法,之后再分析怎么一步一步想出来的。
(1)我们把第一棵树剖成链,第二棵树构造主席树。第二颗树每个结点都是一颗一棵线段树,每个结点形成线段树包含这个点到根结点的某些信息,合起来就叫做主席树。
(2)那么主席数需要包含什么信息呢?这个我还真不太好形象地解释。
不如我先来说说数剖的作用吧:树剖即把一条链变成log段连续的序列(要不断告诉自己是dfs序连续,所以我们要利用dfs序列)。
所以我们主席树维护的是树1的dfs序列,也就是树2的某个点i,我们令rk[i]位置的值(即i的dfs序)为i。这样树1的每一段x,top[x],只要在主席树里求rk[top[x]]~rk[x]的最大值即可。
(3)这么说如果不会可能还是不会,只用理解一下大概思路就行,代码很容易看懂,配合代码理解感觉更轻松。
最后如果你想研究的透彻一点的话,可以看看接下来的分析。先来把模型简化一下:
问题1.给你两个序列a和b,每次询问给你一个数j,求最小的k1使得a[k1]=b[j+k2](k2>=0)
问题2.询问改成两个数i,j,求最小的k1使得a[i+k1]=b[j+k2]
第一问我们可以把数组a重新编号为{1,2,3,4,...,n},也就是原本的a[x]变成x,然后b数组也是同样变化,即 if (b[y]=a[x])b[y]=x。这样只用在b数组[j,n]区间里求最小值即可。
第二问,那么就不是简单地求最小值了,我们要求大于等于等于i的最小值(注意此时,a数组已经变成{1,2,3,..n}了,b数组也相应的变了)。
时刻说出自己要求的东西也可以帮我们理清思路:
(1)现在我们已经不用管第一个序列了,因为他是一个公差为1的等差数列
(2)我们要求数组二 b[j,n]中的大于i的最小值,求出i在b[j,n]中的排名,也就得到了我们想要的答案。
我都说到这个份上了,应该能想到主席树了。如果没想到请赶快记下主席树的两大板子:
(1)区间第k大
(2)区间k的排名(这个就是我们的题目要用的)
如果你真正理解了上面两个问题,那么两棵数和两个序列其实殊途同归,树链剖分dfs序列其实就是把数组a变成等差数列的过程,二且因为父节点一定小于子节点,所以k1最小等价于k2最小。
代码:
lca优化暴力(依靠数据水)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 200050
int n,m;
template<typename T>void read(T&x)
{
ll k=; char c=getchar();
x=;
while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
if (c==EOF)exit();
while(isdigit(c))x=x*+c-'',c=getchar();
x=k?-x:x;
}
void read_char(char &c)
{while(!isalpha(c=getchar())&&c!=EOF);}
struct Tree
{
int fa[N][],dp[N];
void init()
{
dp[]=;
for(int i=;i<=n;i++)
{
read(fa[i][]);
dp[i]=dp[fa[i][]]+;
}
for(int i=;i<=;i++)
for(int j=;j<=n;j++)
fa[j][i]=fa[fa[j][i-]][i-];
}
}G[];
int get_ans(int x,int y)
{
int k=;
while (x!=y)
{
if (x<y)swap(x,y),k=-k;
for(int i=;i>=;i--)
if (G[k].fa[x][i]>y)x=G[k].fa[x][i];
x=G[k].fa[x][];
if (x==y)return x;
}
return x;
}
void work()
{
read(n); read(m);
G[].init(); G[].init();
int ans=;
for(int i=;i<=m;i++)
{
int x,y,t1,t2;
read(x); read(y);
x=(x+ans)%n+;
y=(y+ans)%n+;
ans=get_ans(x,y);
t1=G[].dp[x]-G[].dp[ans]+;
t2=G[].dp[y]-G[].dp[ans]+;
printf("%d %d %d\n",ans,t1,t2);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("aa.in","r",stdin);
#endif
while()
{
work();
}
}
树链剖分+主席树
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100050
int n,m,dp2[N];
int root[N],TreeNum;
int last[N],tot;
int cnt,fa[N],dp[N],size[N],son[N],rk[N],kth[N],top[N];
struct Tree{int l,r,ls,rs,max;}tr[N*];
struct Edge{int from,to,s;}edges[N<<];
template<typename T>void read(T&x)
{
ll k=; char c=getchar();
x=;
while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
if (c==EOF)exit();
while(isdigit(c))x=x*+c-'',c=getchar();
x=k?-x:x;
}
void read_char(char &c)
{while(!isalpha(c=getchar())&&c!=EOF);}
void AddEdge(int x,int y)
{
edges[++tot]=Edge{x,y,last[x]};
last[x]=tot;
}
void dfs1(int x,int pre)
{
fa[x]=pre;
dp[x]=dp[pre]+;
size[x]=;
son[x]=;
for(int i=last[x];i;i=edges[i].s)
{
Edge &e=edges[i];
if (e.to==pre)continue;
dfs1(e.to,x);
size[x]+=size[e.to];
if(size[e.to]>size[son[x]])son[x]=e.to;
}
}
void dfs2(int x,int y)
{
rk[x]=++cnt;
kth[cnt]=x;
top[x]=y;
if (son[x]==)return;
dfs2(son[x],y);
for(int i=last[x];i;i=edges[i].s)
{
Edge &e=edges[i];
if (e.to==son[x]||e.to==fa[x])continue;
dfs2(e.to,e.to);
}
}
void bt(int &x,int l,int r)
{
x=++TreeNum;
tr[x].l=l ;tr[x].r=r; tr[x].max=;
if (l==r)return;
int mid=(l+r)>>;
bt(tr[x].ls,l,mid);
bt(tr[x].rs,mid+,r);
}
void add(int &x,int last,int p,int tt)
{
x=++TreeNum;
tr[x]=tr[last];
tr[x].max=max(tr[x].max,tt);
if (tr[x].l==tr[x].r)return;
int mid=(tr[x].l+tr[x].r)>>;
if (p<=mid)add(tr[x].ls,tr[last].ls,p,tt);
else add(tr[x].rs,tr[last].rs,p,tt);
}
int query(int x,int l,int r)
{
if (l<=tr[x].l&&tr[x].r<=r)
return tr[x].max;
int mid=(tr[x].l+tr[x].r)>>,a1=,a2=;
if (l<=mid)a1=query(tr[x].ls,l,r);
if (mid<r)a2=query(tr[x].rs,l,r);
return max(a1,a2);
}
int get_ans(int x,int y)
{
int fx=x,tp,ans=;
while(x)
{
tp=query(root[y],rk[fx],rk[x]);
ans=max(ans,tp);
x=fa[fx];fx=top[x];
}
return ans;
}
void work()
{
read(n); read(m);
for(int i=;i<=n;i++)
{
read(fa[i]);
AddEdge(fa[i],i);
}
dfs1(,);
dfs2(,);
dp2[]=;
bt(root[],,n);
add(root[],root[],,);
for(int i=;i<=n;i++)
{
int y;
read(y);
dp2[i]=dp2[y]+;
add(root[i],root[y],rk[i],i);
}
int ans=;
for(int i=;i<=m;i++)
{
int x,y,t1,t2;
read(x); read(y);
x=(x+ans)%n+; y=(y+ans)%n+;
ans=get_ans(x,y);
t1=dp[x]-dp[ans]+;
t2=dp2[y]-dp2[ans]+;
printf("%d %d %d\n",ans,t1,t2);
}
}
void clear()
{
tot=; cnt=; TreeNum=;
memset(last,,sizeof(last));
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("aa.in","r",stdin);
#endif
while()
{
clear();
work();
}
}
acm 2015北京网络赛 F Couple Trees 树链剖分+主席树的更多相关文章
- acm 2015北京网络赛 F Couple Trees 主席树+树链剖分
提交 题意:给了两棵树,他们的跟都是1,然后询问,u,v 表 示在第一棵树上在u点往根节点走 , 第二棵树在v点往根节点走,然后求他们能到达的最早的那个共同的点 解: 我们将第一棵树进行书链剖,然后第 ...
- 2015北京网络赛 F Couple Trees 暴力倍增
Couple Trees Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://hihocoder.com/problemset/problem/123 ...
- HDU 5111 Alexandra and Two Trees 树链剖分 + 主席树
题意: 给出两棵树,每棵树的节点都有一个权值. 同一棵树上的节点的权值互不相同,不同树上节点的权值可以相同. 要求回答如下询问: \(u_1 \, v_1 \, u_2 \, v_2\):询问第一棵树 ...
- Hiho 1232 北京网络赛 F Couple Trees
给两颗标号从1...n的树,保证标号小的点一定在上面.每次询问A树上的x点,和B树上的y点同时向上走,最近的相遇点和x,y到这个点的距离. 比赛的时候想用倍增LCA做,但写渣了....后来看到题解是主 ...
- 2019年ICPC南昌网络赛 J. Distance on the tree 树链剖分+主席树
边权转点权,每次遍历到下一个点,把走个这条边的权值加入主席树中即可. #include<iostream> #include<algorithm> #include<st ...
- 2015北京网络赛 Couple Trees 倍增算法
2015北京网络赛 Couple Trees 题意:两棵树,求不同树上两个节点的最近公共祖先 思路:比赛时看过的队伍不是很多,没有仔细想.今天补题才发现有个 倍增算法,自己竟然不知道. 解法来自 q ...
- 2015北京网络赛 D-The Celebration of Rabbits 动归+FWT
2015北京网络赛 D-The Celebration of Rabbits 题意: 给定四个正整数n, m, L, R (1≤n,m,L,R≤1000). 设a为一个长度为2n+1的序列. 设f(x ...
- 2015北京网络赛 J Scores bitset+分块
2015北京网络赛 J Scores 题意:50000组5维数据,50000个询问,问有多少组每一维都不大于询问的数据 思路:赛时没有思路,后来看解题报告也因为智商太低看了半天看不懂.bitset之前 ...
- (中等) Hiho 1232 Couple Trees(15年北京网络赛F题),主席树+树链剖分。
"Couple Trees" are two trees, a husband tree and a wife tree. They are named because they ...
随机推荐
- HZWER
我们的征途是星辰大海 2016年3月13日8,8077 尊敬的各位老师.亲爱的同学们: 大家好,我是高三(1)班的黄哲威.今天很荣幸能和大家分享一些有关竞赛的心得体会. 去年7月15日,第32届全国信 ...
- bzoj4152
The Captain HYSBZ - 4152 给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用. Input ...
- 2016 NEERC, Northern Subregional Contest G.Gangsters in Central City(LCA)
G.Gangsters in Central City 题意:一棵树,节点1为根,是水源.水顺着边流至叶子.该树的每个叶子上有房子.有q个询问,一种为房子u被强盗入侵,另一种为强盗撤离房子u.对于每个 ...
- mysql delete别名
有一个表的数据比较大,然后需要进行关联删除,删除的时候发现如下SQL报错:ELETE FROM test.test1 a WHERE EXISTS (SELECT 1 FROM test.test2 ...
- Java多线程之ThreadPoolExecutor详解使用
1.概述 我将讲解JAVA原生线程池的基本使用,并由此延伸出JAVA中和线程管理相关的类结构体系,然后我们详细描述JAVA原生线程池的结构和工作方式 2.为什么要使用线程池 前文我们已经讲到,线程是一 ...
- 教你快速写一个EventBus框架
前言EventBus相信大多数人都用过,其具有方便灵活.解耦性强.体积小.简单易用等优点,虽然现在也有很多优秀的替代方案如RxBus.LiveDataBus等,但不可否认EventBus开创了消息总线 ...
- input控件的checkbox属性自定义勾选框
思路 首先隐藏input默认勾选框 通过绑定label标签,设置label的样式来设置勾选框 效果 在这里插入图片描述代码 # html中input的checkbox定义,使用for循环创建多个 ...
- OUC_Summer Training_ DIV2_#11 722
企鹅很忙系列~(可惜只会做3道题T_T) A - A Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d &am ...
- selenium 右侧滚动条操作
对于web上有右侧滚动条的操作 可用使用JS语句执行 拖到底部 js = "var q=document.documentElement.scrollTop=10000"brows ...
- 【Java】给整数加上千分位分隔符
package com.testEmp; import java.text.DecimalFormat; public class NumberFormat { public static void ...