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 ...
随机推荐
- 漫谈计算机编码:从ASCII码到UTF-8
第一阶段 盘古开天辟地——ASCII码 计算机大家都知道,本质是二进制运算和存储.在计算机中人类的几乎所有文字和字符都没法直接表示,所以美国人在发明计算机的时候为了让计算机可以用于保存和传输文字,就发 ...
- 关于kafka定期清理日志后再消费报错kafka.common.OffsetOutOfRangeException的解决
环境: kafka 0.10 spark 2.1.0 zookeeper 3.4.5-cdh5.14.0 公司阿里云测试机,十月一放假前,没有在继续消费,假期过后回来再使用spark strea ...
- Hdu 5248
hdu5248-序列变换 题意: 给你一个序列A,要求改变序列A中的某些元素的顺序,形成一个新的数列B,并保证数列B严格单调递增,求出最小代价. 代价计算公式 $ cost(a,b)=max(|A_i ...
- Linux命令(用户管理、组和时间管理)
用户管理 Linux系统是一个多用用户的系统 用户分为三类: 超级用户(root)用户的id是0 伪用户 用户的id是1----499,虽然存在,但不能被登录 ...
- CDN之简介
1. 什么是 CDN? 来自 <什么是 CDN?> CDN(内容交付网络)是一种高度分布式服务器平台,为交付 Web 应用程序.流媒体等内容专门优化.服务器网络分布于众多物理和网络位置,对 ...
- 从char到QChar
char类型是c/c++中内置的类型,描述了1个字节的内存信息的解析.比如: char gemfield=’g’; 那么在由gemfield标记的这块内存的大小就是1个字节,信息就是01100111, ...
- ArcGIS Python查看geodatabase(.gdb)版本
代码:10.0不能运行 import arcpy desc = arcpy.Describe(r'C:\Users\dell\Documents\ArcGIS\default.gdb') print ...
- Python类call函数的作用
call函数可以把类变成函数来调用call方法 class Demo(): def __init__(self, name): self.name = name def __call__(self): ...
- Qt编写自定义控件19-图片背景时钟
前言 图片背景时钟控件,是全套控件(目前共145个)中唯一的几个贴图的控件,这个背景要是不贴图,会画到猝死,必须用美工做好的图贴图作为背景,此控件以前学C#的时候写过,后面在写Qt控件的过程中把他移植 ...
- 一百一十九:CMS系统之将短信验证码和图形验证码放到memcached缓存中
将两个验证码的视图都放到common蓝图下 from flask import Blueprint, request, make_responsefrom exts import alidayufro ...