<题目链接>

题目大意:

给定一棵无向树,这棵树的有边权,这棵树的边的序号完全由输入边的序号决定。给你一个人的起点,进行两次操作:

一:该人从起点走到指定点,问你这段路径的边权总和是多少。

二:对指定序号的边的权值做一些改变。

解题分析:

本题用的是树链剖分,同时用线段树去维护剖分出的树链。并且,本题也是无向边权转点权的典型例题,这部分要重点掌握。

#include <cstdio>
#include <cstring>
#define Lson l,mid,rt<<1
#define Rson mid+1,r,rt<<1|1
using namespace std;
const int M = 1e5+;
typedef long long ll;
int cnt,tot,head[M],p[M];
int n,q,pos,pp;
int sz[M],top[M],son[M],id[M],rnk[M],f[M],dep[M]; ll a[M]; //代表该点的权值
struct EDGE{
int v,next;
ll w;
}edge[M<<];
struct Tree
{
ll sum;
}tree[M<<];
void init(){
tot=cnt=;
memset(head,-,sizeof(head));
}
void add(int u,int v,ll w){
edge[++cnt].v=v,edge[cnt].w=w,edge[cnt].next=head[u];
head[u]=cnt;
}
void fsd(int u,int fa){ //将边权转化为点权
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;ll w=edge[i].w;
if(v==fa) continue;
a[v]=w;
p[(i-)/+]=v; //(i-1)/2+1 为该边加入的实际序号,因为加入某条边的时候,是将该边正的存一遍,反向存一遍,同一条边在e[]数组中是临近的,所以这里可以这样求该边加入的序号
//这里感觉挺巧妙的,p[i]表示序号为i的边对应的点(该点点权表示该边边权)
fsd(v,u); //继续向下延伸,将边权转化为点权
}
return;
}
void dfs(int u,int fa,int d){ //将重儿子标记,以及一系列的预处理
sz[u]=;f[u]=fa;son[u]=-;dep[u]=d;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v==fa) continue;
dfs(v,u,d+);
sz[u]+=sz[v];
if(son[u]==-||sz[v]>sz[son[u]]) son[u]=v;
}
return ;
}
void dfs1(int u,int t){ //将重链全部找出来
id[u]=++tot;
rnk[tot]=u;
top[u]=t;
if(son[u]==-) return ;
dfs1(son[u],t);
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v==f[u]||v==son[u]) continue;
dfs1(v,v);
}
return ;
}
void Pushup(int rt){
tree[rt].sum=tree[rt<<].sum+tree[rt<<|].sum;
}
void build(int l,int r,int rt){
tree[rt].sum=;
if(l==r){
tree[rt].sum=a[rnk[l]];
return ;
}
int mid=(l+r)>>;
build(Lson);
build(Rson);
Pushup(rt);
}
void update(int l,int r,int rt,int loc,ll v){ //单点更新
if(l==r){
tree[rt].sum=v;
return ;
}
int mid=(l+r)>>;
if(loc<=mid) update(Lson,loc,v);
else update(Rson,loc,v);
Pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return tree[rt].sum;
}
ll ans=;
int mid=(l+r)>>;
if(L<=mid) ans+=query(L,R,Lson);
if(R>mid) ans+=query(L,R,Rson);
return ans;
}
/*--树上路径边权总和查询 --*/
ll sum(int x,int y){
int fx=top[x],fy=top[y];ll res=;
while(fx!=fy){ //如果这两个点不在一条重链上则一直向上跳,并且不断更新
if(dep[fx]>dep[fy]){
res+=query(id[fx],id[x],,n,); //因为在线段树中,fx的编号一定比x编号小
x=f[fx],fx=top[x]; //从这条重链爬到父节点所在重链的链首上去
}
else{
res+=query(id[fy],id[y],,n,);
y=f[fy],fy=top[y];
}
}
if(x==y) return res; //!!!,当x==y的时候要特判一下
if(dep[x]<dep[y])
res+=query(id[son[x]],id[y],,n,); //!!!,这里要注意,因为本题将边权转化为点权,所以计算x-->y的边权值,相当于直接计算son[x]-->y的点权值总和
else
res+=query(id[son[y]],id[x],,n,);
return res;
}
int main(){
init();
scanf("%d%d%d",&n,&q,&pos);
for(int i=;i<n;i++){
int u,v;ll w;
scanf("%d%d%lld",&u,&v,&w);
add(u,v,w);add(v,u,w);
}
/*-- 将边权转化为点权 --*/
fsd(,-); //从标号为1的点开始将边权转化为点权,其实这里从哪个点为起点都无所谓
a[]=; //因为是以1为起点将边权转化为点权,所以1没有权值,这里将1的权值赋0
/*--树链剖分 --*/
dfs(,-,);
dfs1(,); build(,n,); //将剖分出的树链用线段树维护
while(q--){
int op;
scanf("%d",&op);
if(op==){ //从当前点走到指定点的路径权值总和
int to;
scanf("%d",&to);
printf("%lld\n",sum(pos,to));
pos=to; //更新该人的起点
}
else{
int cal;ll w;
scanf("%d%lld",&cal,&w); //cal为需要更新的边的序号
update(,n,,id[p[cal]],w);
}
}
return ;
}

2018-09-10

POJ 2763 Housewife Wind 【树链剖分】+【线段树】的更多相关文章

  1. POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )

    POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...

  2. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  3. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  4. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  5. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  6. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  7. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  8. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  9. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  10. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

随机推荐

  1. oracle  的sqlplus 工具进行翻译的rlwrap 安装教程

    一:下载地址: 链接: https://share.weiyun.com/50R5pBb (密码:dQPc) 或者该QQ群下载: 二:该工具的安装步骤: [oracle@localhost ~]$ l ...

  2. Linux Oracle bash: “sqlplus / as sysdba”: command not found 解决方法

    bash: sqlplus: command not found 解决方法 注:本文来源于 <   bash: sqlplus: command not found 解决方法   > 1: ...

  3. Confluence 6 Home 和其他重要的目录

    Confluence 安装目录 Confluence 安装的目录(Confluence Installation directory)定义的是 Confluence 是在那里进行安装的.这个目录有时候 ...

  4. Confluence 6 编辑站点欢迎消息使用模板编辑器的小提示

    站点欢迎消息是一个模板而不是一个页面,所以你需要使用模板编辑器来对你的消息进行编辑. 你可以和在你 Confluence 中其他页面中一样,在站点欢迎消息模板中添加文本,连接和宏.但是添加图片的话会有 ...

  5. leetcode(js)算法605之种花问题

    假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有.可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去. 给定一个花坛(表示为一个数组包含0和1,其中0表示没种植花,1表示种植了花 ...

  6. PYMySQL的注册功能的实现

    import pymysql conn = pymysql.connect( host = "127.0.0.1", port = 3306, user = "root& ...

  7. LeetCode(125):验证回文串

    Easy! 题目描述: 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写. 说明:本题中,我们将空字符串定义为有效的回文串. 示例 1: 输入: "A man, ...

  8. 饮冰三年-人工智能-linux-03 Linux文件管理(权限管理+归档+压缩)

    1:对文件的权限管理 drwxr-xr-x. 最后一个.表示在安全情况下创建的.selinux a: d表示目录:-表示普通文件:l表示快捷方式:b设备文件 b:- 属主的权限 r:读权限:w:写权限 ...

  9. 使用openssl创建一个自签名https证书,并配置到nginx里面

    公司内网也有这个需求,就简单实现一下. 参考的都是网上的方案,一次过. 1,使用openssl建立服务器私钥(需要输入密码,请记住这个密码)生成RSA密钥 >openssl genrsa -de ...

  10. Vs2017获取Git空仓库后创建解决方案及项目无法推送,推送失败的问题.

      与Git无关,因为远程是空文件夹,导致没有远程版本做对应提示更改或怎样,必须在创建人创建仓库的时候上传文件代码. https://developercommunity.visualstudio.c ...