题目链接

题意

给出一棵有边权的树,然后给出q个查询,每次查询问两个结点的路径上的边的长度的中位数是多少。

思路

这道题目是用主席树(用权值当结点)和LCA来做的。

和之前做过的区间第K大类似,这道题目是把数组转化为树。儿子结点的线段树信息是继承了父亲结点的线段树信息(数组中是第i个结点继承了第i-1个结点的信息)。这样,在查询操作的时候,我们可以找出两点的LCA,然后借助这种思想,在查询操作的时候,就和区间查询一样(区间查询是右端点的信息减去左端点-1的信息),把两个点的线段树信息相加再减去两倍LCA的线段树信息,就可以得到两点的路径的信息了,然后就转化为对这个路径求第k大了。

比如这幅图里面,2号点继承了1号点的信息,3号点继承了2号点的信息。要查询4号点和5号点之间的信息,这两个点的LCA是2号点。那么查询的时候就是4号点的权值+5号点的权值-两倍2号点的权值。

#include <bits/stdc++.h>
using namespace std;
#define N 100010
struct Edge {
int u, v, w, nxt;
} edge[N*2];
struct Node {
int l, r, sum;
} tree[N*40];
int root[N], cnt, head[N], tot, n, mx, dp[N][25], dep[N], fa[N], dis[N]; void Add(int u, int v, int w) {
edge[tot] = (Edge) {u, v, w, head[u]}, head[u] = tot++;
edge[tot] = (Edge) {v, u, w, head[v]}, head[v] = tot++;
} int query(int left, int right, int f, int l, int r, int k) {
if(l == r) return l;
int m = (l + r) >> 1;
int sum = tree[tree[right].l].sum + tree[tree[left].l].sum - 2 * tree[tree[f].l].sum;
if(k <= sum) return query(tree[left].l, tree[right].l, tree[f].l, l, m, k);
else return query(tree[left].r, tree[right].r, tree[f].r, m + 1, r, k - sum);
} void update(int pre, int &rt, int l, int r, int x) {
tree[++cnt] = tree[pre];
rt = cnt; tree[rt].sum++;
if(l == r) return ;
int m = (l + r) >> 1;
if(x <= m) update(tree[pre].l, tree[rt].l, l, m, x);
else update(tree[pre].r, tree[rt].r, m + 1, r, x);
} void dfs(int u, int f) { // 一边更新主席树一边得到lca需要的信息
dp[u][0] = fa[u];
for(int i = 1; i <= 20; i++) dp[u][i] = dp[dp[u][i-1]][i-1];
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v, w = edge[i].w;
if(v == f) continue;
fa[v] = u; dep[v] = dep[u] + 1; dis[u] = dis[v] + w;
update(root[u], root[v], 1, mx, w);
dfs(v, u);
}
} int LCA(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = 20; i >= 0; i--)
if(dep[dp[x][i]] >= dep[y]) x = dp[x][i];
if(x == y) return x;
for(int i = 20; i >= 0; i--)
if(dp[x][i] != dp[y][i]) x = dp[x][i], y = dp[y][i];
return dp[x][0];
} int main() {
int t; scanf("%d", &t);
while(t--) {
scanf("%d", &n); mx = 0;
memset(dp, 0, sizeof(dp));
memset(dis, 0, sizeof(dis));
memset(dep, 0, sizeof(dep));
memset(head, -1, sizeof(head)); tot = cnt = 0;
for(int i = 1; i < n; i++) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
Add(u, v, w);
if(w > mx) mx = w;
}
fa[1] = 1;
dfs(1, 0);
int q; scanf("%d", &q);
while(q--) {
int a, b; scanf("%d%d", &a, &b);
int f = LCA(a, b); // LCA
int p = dep[a] + dep[b] - 2 * dep[f]; // a和b路径的长度
double ans = 0;
if(p % 2) ans = (double)query(root[a], root[b], root[f], 1, mx, p / 2 + 1);
else ans = ((double)query(root[a], root[b], root[f], 1, mx, p / 2) + (double)query(root[a], root[b], root[f], 1, mx, p / 2 + 1)) / 2.0;
printf("%.1f\n", ans);
}
}
return 0;
}

Codeforces Gym101161E:ACM Tax(主席树+LCA)的更多相关文章

  1. Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式)

    Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式) 题外话,这是我第40篇随笔,纪念一下.<( ̄︶ ̄)↗[GO!] 题意 是说有棵树,每个节点上 ...

  2. [bzoj2588][count on a tree] (主席树+lca)

    Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...

  3. BZOJ 2588: Spoj 10628. Count on a tree 主席树+lca

    分析:树上第k小,然后我想说的是主席树并不局限于线性表 详细分析请看http://www.cnblogs.com/rausen/p/4006116.html,讲的很好, 然后因为这个熟悉了主席树,真是 ...

  4. BZOJ 4539: [Hnoi2016]树 [主席树 lca]

    4539: [Hnoi2016]树 题意:不想写.复制模板树的子树,查询两点间距离. *** 终于有一道会做的题了...... 画一画发现可以把每次复制的子树看成一个大点来建一棵树,两点的lca一定在 ...

  5. SPOJ COT Count on a tree(树上主席树 + LCA 求点第k小)题解

    题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点 ...

  6. Codechef FIBTREE 树链剖分 主席树 LCA 二次剩余 快速幂

    原文链接https://www.cnblogs.com/zhouzhendong/p/CC-FIBTREE.html 题目传送门 - CC-FIBTREE 题意 给定一个有 $n$ 个节点,初始点权都 ...

  7. BZOJ4448[Scoi2015]情报传递——主席树+LCA

    题目描述 奈特公司是一个巨大的情报公司,它有着庞大的情报网络.情报网络中共有n名情报员.每名情报员口J-能有 若T名(可能没有)下线,除1名大头目外其余n-1名情报员有且仅有1名上线.奈特公司纪律森严 ...

  8. 【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA

    [BZOJ2588]Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lasta ...

  9. SPOJ Count on a tree(主席树+LCA)

    一.题目 COT - Count on a tree You are given a tree with N nodes. The tree nodes are numbered from 1 to  ...

随机推荐

  1. Feature extraction - sklearn文本特征提取

    http://blog.csdn.net/pipisorry/article/details/41957763 文本特征提取 词袋(Bag of Words)表征 文本分析是机器学习算法的主要应用领域 ...

  2. NPM镜像设置方法!

    使用npm安装一些包失败了的看过来(npm国内镜像介绍) 发布于 2012-4-26 04:19 最后一次编辑是 2013-12-11 23:21 这个也是网上搜的,亲自试过,非常好用! 镜像使用方法 ...

  3. dataGrid 源更新 事件

    DataGrid myGrid = new DataGrid(); CollectionView myCollectionView = (CollectionView)CollectionViewSo ...

  4. 用友u8各版本在输出的时候报错提示:外部数据库驱动程序(1)中的意外错误

    从10月12日起很多U8用户反馈,在各版本U8中输出报表时软件报错,报错内容“外部数据库驱动程序(1)中的意外错误”,经初步分析有以下解决方案:1.卸载微软的补丁:(1)如果是PC操作系统(一般是客户 ...

  5. VMNET 工作站

    nattunnel 快速连接内网电脑 内网穿透.内网映射,支持微信小程序本地开发 支持WEB.远程桌面.多种TCP协议 官方主页:http://www.vmnet.cc 用途 一个可以快速连接局域网中 ...

  6. C#程序以管理员的身份运行

    在一些特定的情况下我们需要能够有管理员的权限,这样我们的很多执行,或者写入就不会报错了. 1.解决方案资源管理器---->项目(右键)--->属性-->安全性 2.勾选“启用Clic ...

  7. Win10《芒果TV》商店版更新v3.2.4:新增跨年事件直播、电视台直播,新年快乐

    听说半个娱乐圈都来了,<芒果TV>UWP版邀您一起,于2016年12月31日晚,观看<湖南卫视2016·2017跨年演唱会>直播,请更新v3.2.4版,主要新增大事件直播和电视 ...

  8. spring.net的简单使用(二)资源配置

    主要对资源配置做进一步的解析. 对资源位置的配置是在spring节点的context下,resource节点配置. spring.net的资源是可以设置在三种不同的位置的, 1.配置文件中 <r ...

  9. Cookieless.js —— 无需 Cookie 实现访客跟踪

    直击现场 https://github.com/Colex/node-cookieless Cookieless.js 是一个轻量级的使用 Etag 进行访客跟踪的 Node.js 扩展库.使用该库无 ...

  10. delphi中move函数的正确理解(const和var一样,都是传地址,所以Move是传地址,而恰恰不是传值)太精彩了 good

    我们能看到以下代码var pSource,pDest:PChar;     len: integer;.......................//一些代码Move(pSource,pDest,l ...