<题目链接>

题目大意:

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

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

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

解题分析:

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

#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. java内部类和异常类的概念

    1.内部类的外嵌类的成员变量在内部类中任然有效,内部类中的方法也可以调用外嵌类中的 方法,内部类中不可以声明类的变量和方法,外嵌的类体可以用内部类声明对象,作为外嵌类的成员.内部类仅供他的外嵌类使用. ...

  2. sqlmap+DWAV测试实战(一)

    root@kali-yaming:~# sqlmap -u "http://172.18.225.39/vulnerabilities/sqli/?id=1&Submit=Submi ...

  3. cf1144G 将串分解成单调递增和递减子串(贪心)

    这算哪门子dp.. 具体做法就是贪心,建立两个vector存递增序列递减序列,操作过程中a可以合法地匀一个给b 就是判断第i个数放在递增序列里还是放在递减序列里,需要根据后面的数来进行决策 #incl ...

  4. php url函数

    1.base64_encode 与 base64_decode base64_encode(string) 表示使用 MIME base64 对数据进行编码 base64_decode(string) ...

  5. Mac下Java JDK的下载安装和配置

    一.下载安装 打开一个搜索引擎,输入JDK,找到Java JDK 如图:  点击打开,同意协议开始下载如图: 下载好以后,安装即可. 安装成功以后,进入根目录,可以找到JDK安装的位置: 资源库——& ...

  6. python 之 列表与字典

    1.4 列表与字典 列表与字典,这两种类型,都是各种类型的集合,以列表为例,如果列表中包含列表,就形成嵌套. 这两种类型几乎是所有python脚本的主要工作组件 . 这种结构信息是可变的可修改的.不像 ...

  7. 如何让谷歌浏览器支持跨域访问(AJAX) AJAX调试跨域接口

    以谷歌最新版本为例(2018) 1.在电脑上新建一个目录,例如:C:\MyChromeDevUserData 2.在属性页面中的目标输入框里加上   --disable-web-security -- ...

  8. 蓝桥杯  历届试题 剪格子  dfs

    历届试题 剪格子 时间限制:1.0s   内存限制:256.0MB 问题描述 如下图所示,3 x 3 的格子中填写了一些整数. +--*--+--+ |10* 1|52| +--****--+ |20 ...

  9. social psychology 10th David G. Myers

    Social psychology is a science that studies the influences of our situations, with special attention ...

  10. OpenCV-Python教程8-图像混合

    一.图片相加 要叠加两张图片,使用cv2.add(),相加两幅图片的形状(高度.宽度.通道数)必须相同.numpy中可以直接用res = img1 + img2相加.但是两者的结果并不相同 impor ...