POJ 2763 Housewife Wind 【树链剖分】+【线段树】
<题目链接>
题目大意:
给定一棵无向树,这棵树的有边权,这棵树的边的序号完全由输入边的序号决定。给你一个人的起点,进行两次操作:
一:该人从起点走到指定点,问你这段路径的边权总和是多少。
二:对指定序号的边的权值做一些改变。
解题分析:
本题用的是树链剖分,同时用线段树去维护剖分出的树链。并且,本题也是无向边权转点权的典型例题,这部分要重点掌握。
#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 【树链剖分】+【线段树】的更多相关文章
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
- HDU4897 (树链剖分+线段树)
Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...
- 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 ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- HDU 2460 Network(双连通+树链剖分+线段树)
HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...
随机推荐
- Oracle 中 nvl、nvl2、nullif、coalesce、decode 函数的用法详解
NVL(EXPR1,EXPR2) NVL2(EXPR1,EXPR2,EXPR3) NULLIF(EXPR1,EXPR2) COALESCE(EXPR1,,..,EXPRn) decode ------ ...
- Confluence 6 链接到其他应用
应用链接(Application Links)有时候也被称为 "AppLinks" 是一系列测插件能够允许你在 Atlassian 的应用中互相链接.链接 2 个应用能够允许你在 ...
- LeetCode(97):交错字符串
Hard! 题目描述: 给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的. 示例 1: 输入: s1 = "aabcc", s2 = &qu ...
- 获取checkbox勾选的id
需求描述:做批量删除或者批量修改的时候需要获得多个id,根据checkbox勾选来获取对应的d 两种方法: //html代码<table id="table1"> &l ...
- java----面对对象
面对对象: public class Demo { public static void main(String[] args){ Horse h = null; h = new Horse(); / ...
- 线性空间和异或空间(线性基)bzoj4004贪心+高斯消元优秀模板
线性空间:是由一组基底构成的所有可以组成的向量空间 对于一个n*m的矩阵,高斯消元后的i个主元可以构成i维的线性空间,i就是矩阵的秩 并且这i个主元线性无关 /* 每个向量有权值,求最小权极大线性无关 ...
- mysql下载源码方法
方法一 进入mysql官网:http://dev.mysql.com/downloads/mysql/ 选择相关的平台下载: 3.选择Source Code 选型后,拉倒网页下方,选择要下载的源码包 ...
- Gson将字符串转map时,int默认为double类型
gson能够将json字符串转换成map, 但是在转成map时, 会默认将字符串中的int , long型的数字, 转换成double类型 , 数字会多一个小数点 , 如 1 会转成 1.0 Gs ...
- C++ Primer 笔记——转发
某些函数需要将其一个或多个实参连同类型不变的转发给其他函数,这种情况下我们需要保持被转发实参的所有性质,包括实参类型是否是const的以及实参是左值还是右值. template <typenam ...
- Vue-切割json数组字符串并循环输出
Json "detailList":[ " 04/08/2016 - LA - - Dept. - TITLE (Lien Reported)", " ...