题目链接【http://www.spoj.com/problems/QTREE/】

题意:给出一个包含N(N<=10000)节点的无根树,有多次询问,询问的方式有两种1、DIST  a b 求a->b之间的距离。2、KTH a b k 求a->b链上的第k个节点是谁,。如果输入DONE,结束询问。

思路:首先想到用倍增法可以解决第一种询问,只需要在DFS时候维护一个dis[i](表示i节点到根节点之间的距离,因为是无根树,我们定义节点1为根),dis(a->b)=dis[a]+dis[b]-dia[lca(a,b)]。第二种询问的解法是首先求出a,b的lca,然后根据lca到a到b的深度判断第k个数在左半枝还是右半枝(可以定义lca为左半枝),然后用倍增的方法求出第k个节点。

#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = ;
struct node
{
int id, len, next;
} E[maxn << ];
int p[maxn << ], num;
void init()
{
memset(p, -, sizeof(p));
num = ;
}
void add(int u, int v, int dis)
{
E[num].id = u;
E[num].len = dis;
E[num].next = p[v];
p[v] = num++;
}
//------------------------------------------邻接表
int T, N;
int fa[][maxn];//倍增数组
int dis[maxn], dep[maxn];//距离,深度数组
void DFS(int u, int FA)//DFS求出每个节点的深度,每个节点到根节点的距离,和每个节点跳1步到达的位置
{
for(int l = p[u]; l != -; l = E[l].next)
{
int id = E[l].id;
if(id == FA) continue;
fa[][id] = u;
dep[id] = dep[u] + ;
dis[id] = dis[u] + E[l].len;
DFS(id, u);
}
}
void INIT()//初始化倍增数组
{
memset(fa, -, sizeof(fa));
memset(dis, , sizeof(dis));
memset(dep, , sizeof(dep));
DFS(, -);
for(int k = ; k + <= ; k++)
{
for(int u = ; u <= N; u++)
{
if(fa[k][u] < )
fa[k + ][u] = -;
else
fa[k + ][u] = fa[k][fa[k][u]];
}
}
}
int LCA(int u, int v)
{
if(dep[u] > dep[v]) swap(u, v);
for(int k = ; k <= ; k++)//微调,使得dep相等
if((dep[v] - dep[u]) >> k & )
v = fa[k][v];
if(u == v) return u;//公共祖先是u,v中的其中一个
for(int k = ; k >= ; k--)//一起向上跳,先跳距离远的
{
if(fa[k][u] != fa[k][v])
{
u = fa[k][u];
v = fa[k][v];
}
}
return fa[][u];
}
int KTH(int u, int v, int lca, int k)//从u->v路径上的第k个数
{
if(k == ) return u;
int l1 = dep[u] - dep[lca] + ;//左半枝
int l2 = dep[v] - dep[lca];
if(k <= l1)//在左半枝(lca定义成左半枝)
{
k -= ;
for(int t = ; t >= ; t--)
{
if(k >> t & )
u = fa[t][u];
}
return u;
}
else//在右半枝
{
k -= l1;
k = l2 - k;
for(int t = ; t >= ; t--)
{
if(k >> t & )
v = fa[t][v];
}
return v;
}
}
int main ()
{
scanf("%d", &T);
while(T--)
{
init();
int u, v, ds, k;
char s[];
scanf("%d", &N);
for(int i = ; i < N; i++)
{
scanf("%d%d%d", &u, &v, &ds);
add(u, v, ds);
add(v, u, ds);
}
INIT();
while(scanf("%s", s))
{
if(!strcmp(s, "DONE"))
break;
else if(!strcmp(s, "DIST"))
{
scanf("%d%d", &u, &v);
printf("%d\n", dis[u] + dis[v] - * dis[LCA(u, v)]);
}
else
{
scanf("%d%d%d", &u, &v, &k);
int lca = LCA(u, v);
printf("%d\n", KTH(u, v, lca, k)); }
}
}
return ;
}

SPOJ375 Query on a tree 【倍增,在线】的更多相关文章

  1. SPOJ375 Query on a tree

    Description You are given a tree (an acyclic undirected connected graph) with N nodes, and edges num ...

  2. SPOJ375 Query on a tree(树链剖分)

    传送门 题意 给出一棵树,每条边都有权值,有两种操作: 把第p条边的权值改为x 询问x,y路径上的权值最大的边 code #include<cstdio> #include<algo ...

  3. SPOJ375 Query on a tree(LCT边权)

    之前做了两道点权的LCT,这次做一下边权的LCT.上网找了一下资料,发现对于边权的LCT有这么两种处理方法,一种是每条边建一个点,于是边权就转成点权了.另外一种则是每个边权对应到点权上,也就是每个点对 ...

  4. spoj 913 Query on a tree II (倍增lca)

    Query on a tree II You are given a tree (an undirected acyclic connected graph) with N nodes, and ed ...

  5. Query on a tree——树链剖分整理

    树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...

  6. SPOJ 375. Query on a tree (树链剖分)

    Query on a tree Time Limit: 5000ms Memory Limit: 262144KB   This problem will be judged on SPOJ. Ori ...

  7. QTREE3 spoj 2798. Query on a tree again! 树链剖分+线段树

    Query on a tree again! 给出一棵树,树节点的颜色初始时为白色,有两种操作: 0.把节点x的颜色置反(黑变白,白变黑). 1.询问节点1到节点x的路径上第一个黑色节点的编号. 分析 ...

  8. spoj 375 Query on a tree(树链剖分,线段树)

      Query on a tree Time Limit: 851MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Sub ...

  9. bzoj 3637: Query on a tree VI 树链剖分 && AC600

    3637: Query on a tree VI Time Limit: 8 Sec  Memory Limit: 1024 MBSubmit: 206  Solved: 38[Submit][Sta ...

随机推荐

  1. Appium修改源码后重新编译

    按照官方的说明下载源码,安装依赖库,具体可从这来: https://github.com/appium/appium/blob/master/docs/en/contributing-to-appiu ...

  2. Spark 基本架构及原理

    转载自: http://blog.csdn.net/swing2008/article/details/60869183 转自:http://www.cnblogs.com/tgzhu/p/58183 ...

  3. 03.WebView演练-iOS开发Demo(示例程序)源代码

    技术博客http://www.cnblogs.com/ChenYilong/   新浪微博http://weibo.com/luohanchenyilong   //转载请注明出处--本文永久链接:h ...

  4. 线程池-Threadlocal

    ThreadLoclc初衷是线程并发时,解决变量共享问题,但是由于过度设计,比如弱引用的和哈希碰撞,导致理解难度大.使用成本高,反而成为故障高发点,容易出现内存泄露,脏数据.贡献对象更新等问题.单从T ...

  5. 【leetcode 简单】第十二题 报数

    报数序列是指一个整数序列,按照其中的整数的顺序进行报数,得到下一个数.其前五项如下: 1. 1 2. 11 3. 21 4. 1211 5. 111221 1 被读作  "one 1&quo ...

  6. 南邮PHP反序列化

    题目如下: <?php class just4fun { var $enter; var $secret; } if (isset($_GET['pass'])) { $pass = $_GET ...

  7. ConcurrentHashMap分析

    1.ConcurrentHashMap锁分段技术                     ConcurrentHashMap使用锁分段技术,首先将数据分成一段一段地存储,然后给每一段数据配一把锁,当一 ...

  8. SQL 变量 条件查询 插入数据

    (本文只是总结网络上的教程) 在操作数据库时 SQL语句中难免会用到变量 比如 在條件值已知的情況下 INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值 ...

  9. 设置Git远程仓库

    1,注册一个GitHub账户,登陆GitHub账户,添加一个储存库 2,进入Ubuntu命令窗口,创建文件夹.如   mkdir   git echo "# first_git" ...

  10. Window文本在Linux中出现的^M问题

    问题:在Windows中写了一个shell脚本在Linux中死活不能运行,怎么也查不出错误,原来是格式问题. 原因:Windows/DOS系统的换行符是/r/n,Unix/Linux系统的换行符是/n ...