poj2763--Housewife Wind(树链剖分+线段树)

Housewife Wind

Time Limit: 4000MS   Memory Limit: 65536K
Total Submissions: 6898   Accepted: 1742

Description

After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy life. People in XX Village lived in beautiful huts. There are some pairs of huts connected by bidirectional roads. We say
that huts in the same pair directly connected. XX Village is so special that we can reach any other huts starting from an arbitrary hut. If each road cannot be walked along twice, then the route between every pair is unique.

Since Jiajia earned enough money, Wind became a housewife. Their children loved to go to other kids, then make a simple call to Wind: ‘Mummy, take me home!‘

At different times, the time needed to walk along a road may be different. For example, Wind takes 5 minutes on a road normally, but may take 10 minutes if there is a lovely little dog to play with, or take 3 minutes if there is some unknown strange smell surrounding
the road.

Wind loves her children, so she would like to tell her children the exact time she will spend on the roads. Can you help her?

Input

The first line contains three integers n, q, s. There are n huts in XX Village, q messages to process, and Wind is currently in hut s. n < 100001 , q < 100001.

The following n-1 lines each contains three integers a, b and w. That means there is a road directly connecting hut a and b, time required is w. 1<=w<= 10000.

The following q lines each is one of the following two types:

Message A: 0 u

A kid in hut u calls Wind. She should go to hut u from her current position.

Message B: 1 i w

The time required for i-th road is changed to w. Note that the time change will not happen when Wind is on her way. The changed can only happen when Wind is staying somewhere, waiting to take the next kid.

Output

For each message A, print an integer X, the time required to take the next child.

Sample Input

3 3 1
1 2 1
2 3 2
0 2
1 2 3
0 3

Sample Output

1
3

树链剖分的模板题,做好线段树后,就是简单的单点更新,区域查询了

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define maxn 110000
#define lmin 1
#define rmax n
#define root lmin,rmax,1
#define lson l,(l+r)/2,rt<<1
#define rson (l+r)/2+1,r,rt<<1|1
#define now l,r,rt
#define int_now int l,int r,int rt
struct node
{
    int u , v , w ;
    int next ;
} edge[maxn<<1];
int head[maxn] , vis[maxn] , cnt ;//存储树,vis标记节点
int belong[maxn] ;//记录第i条边(u,v)中的子节点v
int p[maxn] ;//子节点为v的树枝的长度
int cl[maxn<<2] , s[maxn] ;//线段树数组cl,s记录标号为1到n的树杈的值,提供给cl建立线段树
int num[maxn] ;//以节点u为根的子树的节点个数
int dep[maxn] ;//节点u的深度,根的深度为1
int top[maxn] ;//u所在的重链的最顶端的节点
int son[maxn] , fa[maxn] ;//u的重儿子节点,u的父亲节点,
int w[maxn] , step ;//记录节点v与父亲的连边在线段树的位置
int n , m , t ;
void add(int u,int v,int w)
{
    edge[cnt].u = u ;
    edge[cnt].v = v ;
    edge[cnt].w = w ;
    edge[cnt].next = head[u] ;
    head[u] = cnt++ ;
    edge[cnt].u = v ;
    edge[cnt].v = u ;
    edge[cnt].w = w ;
    edge[cnt].next = head[v] ;
    head[v] = cnt++ ;
    return ;
}
void dfs1(int u)
{
    int i , v , max1 = -1 , k = -1 ;
    num[u] = 1 ;
    for(i = head[u] ; i != -1 ; i = edge[i].next)
    {
        v = edge[i].v ;
        if( vis[v] ) continue ;
        belong[i/2+1] = v ;
        vis[v] = 1 ;
        dep[v] = dep[u] + 1 ;
        fa[v] = u ;
        p[v] = edge[i].w ;
        dfs1(v) ;
        if( num[v] > max1 )
        {
            max1 = num[v] ;
            k = v ;
        }
    }
    son[u] = k ;
    return ;
}
void dfs2(int u)
{
    if( son[u] == -1 ) return ;
    int i , v = son[u] ;
    vis[v] = 1 ;
    w[v] = step ;
    s[step++] = p[v] ;
    top[v] = top[u] ;
    dfs2(v) ;
    for(i = head[u] ; i != -1 ; i = edge[i].next)
    {
        v = edge[i].v ;
        if( vis[v] ) continue ;
        vis[v] = 1 ;
        w[v] = step ;
        s[step++] = p[v] ;
        top[v] = v ;
        dfs2(v) ;
    }
    return ;
}
void dfs()
{
    memset(vis,0,sizeof(vis)) ;
    vis[1] = 1 ;
    dep[1] = 1 ;
    fa[1] = -1 ;
    dfs1(1) ;
    memset(vis,0,sizeof(vis)) ;
    vis[1] = 1 ;
    step = 1 ;
    top[1] = 1 ;
    dfs2(1) ;
    return ;
}
void push_up(int_now)
{
    cl[rt] = cl[rt<<1] + cl[rt<<1|1] ;
    return ;
}
void build(int_now)
{
    cl[rt] = 0 ;
    if( l != r )
    {
        build(lson) ;
        build(rson) ;
        push_up(now) ;
    }
    else
        cl[rt] = s[l] ;
    return ;
}
void update(int in,int x,int_now)
{
    if( l == in && r == in )
    {
        cl[rt] = x ;
        return ;
    }
    if( in <= (l+r)/2 )
        update(in,x,lson) ;
    else
        update(in,x,rson) ;
    push_up(now) ;
    return ;
}
int query(int ll,int rr,int_now)
{
    if( ll > r || rr < l ) return 0;
    if( ll <= l && rr >= r ) return cl[rt] ;
    return query(ll,rr,lson)+query(ll,rr,rson) ;
}
void solve(int u,int v)
{
    int temp , f1 , f2 , ans = 0 ;
    while( u != v )
    {
        if( dep[u] < dep[v] )
        {
            temp = u ;
            u = v ;
            v = temp ;
        }
        f1 = top[u] ;
        f2 = top[v] ;
        if( f1 == f2 )
        {
            ans += query(w[son[v]],w[u],root) ;
            v = u ;
        }
        else if( dep[f1] >= dep[f2] )
        {
            ans += query(w[f1],w[u],root) ;
            u = fa[f1] ;
        }
        else
        {
            ans += query(w[f2],w[v],root) ;
            v = fa[f2] ;
        }
    }
    printf("%d\n", ans) ;
    return ;
}
int main()
{
    int i , j , k ;
    int u , v ;
    while( scanf("%d %d %d", &n, &m, &t) != EOF )
    {
        cnt = 0 ;
        memset(head,-1,sizeof(head)) ;
        for(i = 1 ; i < n ; i++)
        {
            scanf("%d %d %d", &u, &v, &k) ;
            add(u,v,k) ;
        }
        dfs() ;
        n-- ;
        build(root) ;
        i = t ;
        while( m-- )
        {
            scanf("%d", &k) ;
            if( k == 0 )
            {
                scanf("%d", &j) ;
                solve(i,j) ;
                i = j ;
            }
            else
            {
                scanf("%d %d", &j, &k) ;
                v = belong[j] ;
                update(w[v],k,root) ;
            }
        }
    }
    return 0 ;
}
时间: 2024-11-10 08:09:52

poj2763--Housewife Wind(树链剖分+线段树)的相关文章

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.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

BZOJ2243 (树链剖分+线段树)

Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. 解题分析 树链剖分+线段树. 开一个记录类型,记录某一段区间的信息.l 表示区间最左侧的颜色 , r 表示区间最右侧的颜色 , sum 表示区间中颜色段数量. 合并时判断一下左区间的右端点和有区间的左端点的颜色是否一样. 树上合并时需要用两个变量ans1,ans2来存储.ans1表示x往上走时形成的链的信息,

bzoj4304 (树链剖分+线段树)

Problem T2 (bzoj4304 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 解题分析 练手题.树链剖分+线段树. 参考程序 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #incl

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分+线段树区间合并

题目描述 由乃正在做她的OJ.现在她在处理OJ上的用户排名问题.OJ上注册了n个用户,编号为1-",一开始他们按照编号 排名.由乃会按照心情对这些用户做以下四种操作,修改用户的排名和编号:然而由乃心情非常不好,因为Deus天 天问她题...因为Deus天天问由乃OI题,所以由乃去学习了一下OI,由于由乃智商挺高,所以OI学的特别熟练她 在RBOI2016中以第一名的成绩进入省队,参加了NOI2016获得了金牌保送 Deus:这个题怎么做呀? yuno:这个不是NOI2014的水题吗... Deu

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

HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链剖分+线段树处理 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #pragma comment(linke

【bzoj1959】[Ahoi2005]LANE 航线规划 离线处理+树链剖分+线段树

题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1.2.3……. 一些先遣飞船已经出发,在星球之间开辟探险航线. 探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线. 例如下图所示: 在5个星球之间,有5条探险航

HDU4897 (树链剖分+线段树)

Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作2:将所有 有且仅有一个点在a->b的路径中 的边的颜色翻转. 操作3:询问a->b的路径中的黑色边数量. 解题分析 考虑操作1,只需正常的树链剖分+线段树维护即可.用线段树维护每条边,tag_1[i]表示该区间中的黑色边数量. 考虑操作2,一个节点相邻的边只可能为重链和轻链,且重链的数目小于等于