POJ 2763 /// 基于边权的树链剖分
题目大意:
给定n个结点,有n-1条无向边,给定每条边的边权
两种操作,第一种:求任意两点之间路径的权值和,第二种:修改树上一点的权值。
因为是一棵树,可以直接把 u点和v点间(假设u为父节点,v为子节点)的边 的边权往下给v点
这样就转换成了点权,那么此时查询 u点到v点之间路径的权值和 的话
由于u点存有 u的父节点到u 的边权,所以应该查询的是 u到v的路径上 的第二个点到v的权值和
- 修改查询树上两结点间路径长度的函数
- int queryPath(int x,int y){ }
- 中求最后一步的部分
- /// 点权版本
- if(p[x]>p[y]) swap(x,y);
- return ans+query(p[x],p[y],,pos,);
- /// 边权版本
- if(x==y) return ans;
- if(dep[x]>dep[y]) swap(x,y);
- return ans+query(p[son[x]],p[y],root);
- #include <stdio.h>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- #define mem(i,j) memset(i,j,sizeof(i))
- #define lson l,m,rt<<1
- #define rson m+1,r,rt<<1|1
- #define root 1,n,1
- const int maxn=1e5+;
- int n,q,s;
- struct QTree {
- struct EDGE { int to,ne; }e[maxn<<];
- int head[maxn], tot;
- void add(int u,int v) {
- e[tot].to=v;
- e[tot].ne=head[u];
- head[u]=tot++;
- }
- int fa[maxn], son[maxn], dep[maxn], num[maxn];
- int top[maxn], p[maxn], fp[maxn], pos;
- int sumT[maxn<<];
- void init() {
- tot=; mem(head,);
- pos=; mem(son,);
- }
- // --------------------以下是线段树-------------------------
- void pushup(int rt) {
- sumT[rt]=sumT[rt<<]+sumT[rt<<|];
- }
- void build(int l,int r,int rt) {
- if(l==r) {
- sumT[rt]=; return ;
- }
- int m=(l+r)>>;
- build(lson), build(rson);
- pushup(rt);
- }
- void update(int k,int w,int l,int r,int rt) {
- if(l==r) {
- sumT[rt]=w; return;
- }
- int m=(l+r)>>;
- if(k<=m) update(k,w,lson);
- else update(k,w,rson);
- pushup(rt);
- }
- int query(int L,int R,int l,int r,int rt) {
- if(L<=l && r<=R) return sumT[rt];
- int m=(l+r)>>, res=;
- if(L<=m) res+=query(L,R,lson);
- if(R>m) res+=query(L,R,rson);
- return res;
- }
- // --------------------以上是线段树-------------------------
- // --------------------以下是树链剖分-------------------------
- void dfs1(int u,int pre,int d) {
- dep[u]=d; fa[u]=pre; num[u]=;
- for(int i=head[u];i;i=e[i].ne) {
- int v=e[i].to;
- if(v!=fa[u]) {
- dfs1(v,u,d+);
- num[u]+=num[v];
- if(!son[u] || num[v]>num[son[u]])
- son[u]=v;
- }
- }
- }
- void dfs2(int u,int sp) {
- top[u]=sp; p[u]=++pos; fp[p[u]]=u;
- if(!son[u]) return;
- dfs2(son[u],sp);
- for(int i=head[u];i;i=e[i].ne) {
- int v=e[i].to;
- if(v!=son[u] && v!=fa[u])
- dfs2(v,v);
- }
- }
- int queryPath(int x,int y) {
- int ans=;
- int fx=top[x], fy=top[y];
- while(fx!=fy) {
- if(dep[fx]>=dep[fy]) {
- ans+=query(p[fx],p[x],root);
- x=fa[fx];
- } else {
- ans+=query(p[fy],p[y],root);
- y=fa[fy];
- }
- fx=top[x], fy=top[y];
- }
- if(x==y) return ans;
- if(dep[x]>dep[y]) swap(x,y);
- return ans+query(p[son[x]],p[y],root);
- }
- // --------------------以上是树链剖分-------------------------
- void initQTree() {
- dfs1(,,);
- dfs2(,);
- build(root);
- }
- }T;
- int E[maxn][];
- int main()
- {
- while(~scanf("%d%d%d",&n,&q,&s)) {
- T.init();
- for(int i=;i<n;i++) {
- int u,v,w; scanf("%d%d%d",&u,&v,&w);
- E[i][]=u, E[i][]=v, E[i][]=w;
- T.add(u,v); T.add(v,u);
- }
- T.initQTree();
- for(int i=;i<n;i++) {
- if(T.dep[E[i][]]>T.dep[E[i][]])
- swap(E[i][],E[i][]);
- T.update(T.p[E[i][]],E[i][],root);
- }
- while(q--) {
- int op; scanf("%d",&op);
- if(op) {
- int k,w; scanf("%d%d",&k,&w);
- T.update(T.p[E[k][]],w,root);
- } else {
- int v; scanf("%d",&v);
- printf("%d\n",T.queryPath(s,v));
- s=v;
- }
- }
- }
- return ;
- }
POJ 2763 /// 基于边权的树链剖分的更多相关文章
- POJ 2763:Housewife Wind(树链剖分)
http://poj.org/problem?id=2763 题意:给出 n 个点, n-1 条带权边, 询问是询问 s 到 v 的权值, 修改是修改存储时候的第 i 条边的权值. 思路:树链剖分之修 ...
- HDU 3966 & POJ 3237 & HYSBZ 2243 & HRBUST 2064 树链剖分
树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...
- fzu 2082 过路费 (树链剖分+线段树 边权)
Problem 2082 过路费 Accept: 887 Submit: 2881Time Limit: 1000 mSec Memory Limit : 32768 KB Proble ...
- BZOJ 2157 旅行(树链剖分码农题)
写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v ...
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- HDU 3966 & POJ 3237 & HYSBZ 2243 树链剖分
树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...
- POJ 3237 Tree (树链剖分)
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 2825 Accepted: 769 Description ...
- 【BZOJ-4353】Play with tree 树链剖分
4353: Play with tree Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 31 Solved: 19[Submit][Status][ ...
- Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分)
Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分) Description L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之 ...
随机推荐
- SQL生成 C# Model
本文转自: https://www.cnblogs.com/jhli/p/11552105.html declare @TableName sysname = 'T_FakeOrderList' de ...
- HIve分组查询返回每组的一条记录
select a.lng,a.lat from (select row_number() over ( partition by uid,grid_id) as rnum,weighted_centr ...
- CentOS6.8搭建LNMP环境
selinux可能会致使编译安装失败,我们先禁用它.永久禁用,需要重启生效 sed -i ‘s/SELINUX=enforcing/SELINUX=disabled/g’ /etc/selinux/c ...
- 在Linux下面无法使用向上箭头自动补全上条命令
会用^[[A替代. 参考:http://stackoverflow.com/a/8641302/941650
- 常用内置模块(四)——subprocess、re
常用模块(四) 一.subprocess模块 1.subprocess为子流程模块,用于执行系统命令,该模块在Python全栈开发中不常用 2.常用方法 run 返回一个表示执行结果的对象 call ...
- keepalived 参数中文说明
GLOBAL CONFIGURATION Global definitions global_defs { notification_email { admin@example.com } notif ...
- keep-alive用法及(activated,deactivated生命周期)
<template> <div id="app"> <!-- <img src="./assets/logo.png"> ...
- redis String 相关命令
- 运行Storm实例
- 如何清除Windows共享登录的用户名密码
打开cmd 1.[查看已记录的登录信息] net use 2.[清除记录] 得关掉你所有打开的samba之后再 net use * /del