家庭主妇问题
创始人
2024-04-05 00:32:52

一 问题描述

X 村的人们住在美丽的小屋里。若两个小屋通过双向道路连接,则可以说这两个小屋直接相连。X 村非常特别,可以从任意小屋到达任意其他小屋,每两个小屋之间的路线都是唯一的。温迪的孩子喜欢去找其他孩子玩,然后打电话给温迪:“妈咪,带我回家!”。在不同的时间沿道路行走所需的时间可能不同。温迪想告诉她的孩子她将在路上花的确切时间。

二 输入和输出说明

1 输入

第 1 行包含 3 个整数 n 、q 、s,表示有 n 个小屋、q 个消息,温迪目前在 s 小屋里,n <100001,q <100001。以下 n -1 行各包含 3 个整数 a、b 和 w ,表示有一条连接小屋 a 和 b 的道路,所需的时间是 w (1≤w≤10000)。以下 q 行有两种消息类型:

① 消息 A,即 0 u ,孩子在小屋 u 中给温迪打电话,温迪应该从现在的位置去小屋 u ;

② 消息 B,即 1 i w ,将第 i 条道路所需的时间修改为 w 

注意:温迪在途中时,时间不会发生改变,时间在温迪停留在某个地方等待孩子时才会改变)。

2 输出

对每条消息 A,都输出一个整数,即找到孩子所需的时间。

三 输入和输出用例

1 输入样例

3 3 1

1 2 1

2 3 2

0 2

1 2 3

0 3

2 输出样例

1

3

四 分析

本问题中任意两个小屋都可以相互到达,且路径唯一,明显是树形结构。可以将边权看作点权,对一条边,让深度 dep 较大的点存储边权。对边 u 、v ,边权为 w ,若 dep[u ]>dep[v ],则视 u 的权值为 w 。本问题包括树上点更新、区间和查询。可以用树链剖分将树形结构线性化,然后用线段树进行点更新、区间和查询。

解决方案:树链剖分+线段树。

五 算法设计

1 第 1 次深度优先遍历求 dep、fa、size、son,第 2 次深度优先遍历求 top、id、rev。

2 创建线段树。

3 点更新,u 对应的下标 i =id[u],将其值更新为 val。

4 区间查询,求 u 、v 之间的和值。若 u 、v 不在同一条重链上,则一边查询,一边向同一条重链靠拢;若 u 、v 在同一条重链上,则根据节点的下标在线段树中进行区间查询。

注意:因为在本题中是将边权转变为点权,所以实际查询的区间应为 query(1, id[son[u]], id[v])。

六 代码

package com.platform.modules.alg.alglib.poj2763;public class Poj2763 {private int maxn = 100010;int head[] = new int[maxn]; //头结点int cnt = 0;int total = 0;int fa[] = new int[maxn]; // 父亲int dep[] = new int[maxn]; // 深度int size[] = new int[maxn]; // 子树结点总数int son[] = new int[maxn]; // 重儿子int top[] = new int[maxn]; // 所在重链顶端结点int id[] = new int[maxn];int rev[] = new int[maxn]; // u 对应的 dfs 序下标,下标对于的 uint Sum;Edge1 a[] = new Edge1[maxn];edge e[] = new edge[maxn << 1];node tree[] = new node[maxn << 2];public Poj2763() {for (int i = 0; i < a.length; i++) {a[i] = new Edge1();}for (int i = 0; i < e.length; i++) {e[i] = new edge();}for (int i = 0; i < tree.length; i++) {tree[i] = new node();}}public String output = "";public String cal(String input) {int n, q, s;init();String[] line = input.split("\n");String[] words = line[0].split(" ");n = Integer.parseInt(words[0]);q = Integer.parseInt(words[1]);s = Integer.parseInt(words[2]);for (int i = 1; i < n; i++) {String[] info = line[i].split(" ");a[i].u = Integer.parseInt(info[0]);a[i].v = Integer.parseInt(info[1]);a[i].w = Integer.parseInt(info[2]);add(a[i].u, a[i].v);add(a[i].v, a[i].u);}dep[1] = 1;dfs1(1, 0);dfs2(1, 1);build(1, 1, total);//创建线段树for (int i = 1; i < n; i++) {if (dep[a[i].u] > dep[a[i].v]) {int temp = a[i].u;a[i].u = a[i].v;a[i].v = temp;}update(1, id[a[i].v], a[i].w);}int opt, i, val, x;while (q-- > 0) {String[] query = line[n++].split(" ");opt = Integer.parseInt(query[0]);if (opt == 1) {i = Integer.parseInt(query[1]);val = Integer.parseInt(query[2]);update(1, id[a[i].v], val); // 改变第 i 条边的值为 val} else {x = Integer.parseInt(query[1]);Sum = 0;ask(s, x);//查询s->x路径上边权的和值output += Sum + "\n";s = x;//更新温迪的位置}}return output;}void add(int u, int v) {e[++cnt].to = v;e[cnt].next = head[u];head[u] = cnt;}void init() {cnt = total = 0;}// 求dep,fa,size,sonvoid dfs1(int u, int f) {size[u] = 1;for (int i = head[u]; i > 0; i = e[i].next) {int v = e[i].to;if (v == f)//父节点continue;dep[v] = dep[u] + 1;//深度fa[v] = u;dfs1(v, u);size[u] += size[v];if (size[v] > size[son[u]])son[u] = v;}}// 求 top,id,revvoid dfs2(int u, int t) {top[u] = t;id[u] = ++total;//u对应的dfs序下标rev[total] = u;//dfs序下标对应的结点uif (son[u] == 0)return;dfs2(son[u], t);//沿着重儿子dfsfor (int i = head[u]; i > 0; i = e[i].next) {int v = e[i].to;if (v != fa[u] && v != son[u])dfs2(v, v);}}// 点更新,线段树的第 k 个值为 valvoid update(int i, int k, int val) {if (tree[i].l == k && tree[i].r == k) {tree[i].sum = val;return;}int mid = (tree[i].l + tree[i].r) / 2;if (k <= mid) update(i << 1, k, val);else update((i << 1) | 1, k, val);tree[i].sum = tree[i << 1].sum + tree[(i << 1) | 1].sum;}// 初始化线段树,i 表示存储下标,区间[l,r]void build(int i, int l, int r) {tree[i].l = l;tree[i].r = r;tree[i].sum = 0;if (l == r) return;int mid = (l + r) / 2;//划分点build(i << 1, l, mid);build((i << 1) | 1, mid + 1, r);}// 查询线段树中 [l,r] 的和值void query(int i, int l, int r) {if (tree[i].l >= l && tree[i].r <= r) {//找到该区间Sum += tree[i].sum;return;}int mid = (tree[i].l + tree[i].r) / 2;if (l <= mid) query(i << 1, l, r);if (r > mid) query((i << 1) | 1, l, r);}void ask(int u, int v) {//求u,v之间的和值while (top[u] != top[v]) {//不在同一条重链上if (dep[top[u]] < dep[top[v]]) {int temp = u;u = v;v = temp;}query(1, id[top[u]], id[u]);//u顶端结点和u之间u = fa[top[u]];}if (u == v) return;if (dep[u] > dep[v]) {//在同一条重链上int temp = u; //深度小的结点为uu = v;v = temp;}query(1, id[son[u]], id[v]);//注意是son[u]}
}class edge {int to, next;
}// 结点
class node {int l, r, sum; // l,r区间左右端点,区间和值
}class Edge1 {int u, v, w;
}

七 测试

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...