Lightoj 1348 Aladdin and the Return Journey (树链剖分)(线段树单点修改区间求和)

Finally the Great Magical Lamp was in Aladdin‘s hand. Now he wanted to return home. But he didn‘t want to take any help from the Genie because he thought that it might be another adventure for him. All he remembered was the paths he had taken to reach there. But since he took the lamp, all the genies in the cave became angry and they were planning to attack. As Aladdin was not afraid, he wondered how many genies were there. He summoned the Genie from the lamp and asked this.

Now you are given a similar problem. For simplicity assume that, you are given a tree (a connected graph with no cycles) with n nodes, nodes represent places, edges represent roads. In each node, initially there are an arbitrary number of genies. But the numbers of genies change in time. So, you are given a tree, the number of genies in each node and several queries of two types. They are:

1)      0 i j, it means that you have to find the total number of genies in the nodes that occur in path from node i to j (0 ≤ i, j < n).

2)      1 i v, it means that number of genies in node i is changed to v (0 ≤ i < n, 0 ≤ v ≤ 1000).

Input

Input starts with an integer T (≤ 10), denoting the number of test cases.

Each case starts with a blank line. Next line contains an integer n (2 ≤ n ≤ 30000). The next line contains n space separated integers between 0 and 1000, denoting the number of genies in the nodes respectively. Then there are n-1 lines each containing two integers: u v (0 ≤ u, v < n, u ≠ v) meaning that there is an edge from node u and v. Assume that the edges form a valid tree. Next line contains an integer q (1 ≤ q ≤ 105) followed by q lines each containing a query as described above.

Output

For each case, print the case number in a single line. Then for each query 0 i j, print the total number of genies in the nodes that occur in path i to j.

Sample Input

1

4

10 20 30 40

0 1

1 2

1 3

3

0 2 3

1 1 100

0 2 3

Sample Output

Case 1:

90

170

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <time.h>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define met(a,b) memset(a,b,sizeof a)
#define pb push_back
#define lson(x) ((x<<1))
#define rson(x) ((x<<1)+1)
using namespace std;
typedef long long ll;
const int N=2e5+50;
const int M=N*N+10;
int dep[N],siz[N],fa[N],id[N],son[N],val[N],top[N],c[N]; //top 最近的重链父节点
int num,n,m;
vector<int> v[N];
struct tree {
    int x,y;
    void read() {
        scanf("%d%d",&x,&y);
    }
};
tree e[N];
void dfs1(int u, int f, int d) {
    dep[u] = d;
    siz[u] = 1;
    son[u] = 0;
    fa[u] = f;
    for (int i = 0; i < v[u].size(); i++) {
        int ff = v[u][i];
        if (ff == f) continue;
        dfs1(ff, u, d + 1);
        siz[u] += siz[ff];
        if (siz[son[u]] < siz[ff])
            son[u] = ff;
    }
}
void dfs2(int u, int tp) {
    top[u] = tp;
    id[u] = ++num;
    if (son[u]) dfs2(son[u], tp);
    for (int i = 0; i < v[u].size(); i++) {
        int ff = v[u][i];
        if (ff == fa[u] || ff == son[u]) continue;
        dfs2(ff, ff);
    }
}

struct Tree {
    int l,r,val,sum;
};
Tree tree[4*N];
void pushup(int x) {
    tree[x].val = max(tree[lson(x)].val, tree[rson(x)].val);
    tree[x].sum=tree[lson(x)].sum+tree[rson(x)].sum;
}

void build(int l,int r,int v) {
    tree[v].l=l;
    tree[v].r=r;
    if(l==r) {
        tree[v].val = val[l];
        tree[v].sum=val[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,v*2);
    build(mid+1,r,v*2+1);
    pushup(v);
}
void update(int o,int v,int val) { //log(n)
    if(tree[o].l==tree[o].r) {
        tree[o].val =tree[o].sum= val;
        return ;
    }
    int mid = (tree[o].l+tree[o].r)/2;
    if(v<=mid)
        update(o*2,v,val);
    else
        update(o*2+1,v,val);
    pushup(o);
}
int querySum(int x,int l,int r) {
    if (tree[x].l >= l && tree[x].r <= r) {
        return tree[x].sum;
    }
    int mid = (tree[x].l + tree[x].r) / 2;
    int ans = 0;
    if (l <= mid) ans += querySum(lson(x),l,r);
    if (r > mid) ans += querySum(rson(x),l,r);
    return ans;
}
int Qsum(int u,int v) {
    int tp1 = top[u], tp2 = top[v];
    int ans = 0;
    while (tp1 != tp2) {
        if (dep[tp1] < dep[tp2]) {
            swap(tp1, tp2);
            swap(u, v);
        }
        ans +=querySum(1,id[tp1], id[u]);
        //printf("ans:   %d\n",ans);
        u = fa[tp1];
        tp1 = top[u];
    }
    //if (u == v) return ans;
    if (dep[u] > dep[v]) swap(u, v);
    ans +=querySum(1,id[u], id[v]);
    return ans;
}
void init(){
    for(int i=0;i<N;i++)v[i].clear();
    met(tree,0);met(son,0);met(val,0);
}
int main() {
    int t,T=0;
    scanf("%d",&t);
    while(t--) {
        init();
        ++T;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)scanf("%d",&c[i]);
        for(int i=1; i<n; i++) {
            e[i].read();
            e[i].x++;e[i].y++;
            v[e[i].x].push_back(e[i].y);
            v[e[i].y].push_back(e[i].x);
        }

        num = 0;
        dfs1(1,0,1);
        dfs2(1,1);
        for (int i = 1; i <=n; i++) {
            val[id[i]] = c[i];
        }
        build(1,num,1);
        char s[200];
        scanf("%d",&m);
        printf("Case %d:\n",T);
        while(m--) {
            int o,x,y;
            scanf("%d",&o);
            scanf("%d%d",&x,&y);
            if (o)
                x++,update(1,id[x],y);
            else
                x++,y++,printf("%d\n",Qsum(x,y));
        }
    }
    return 0;
}

时间: 2024-10-20 06:31:28

Lightoj 1348 Aladdin and the Return Journey (树链剖分)(线段树单点修改区间求和)的相关文章

LightOJ 1348 Aladdin and the Return Journey

题意: 给出N个节点的一棵树,每个节点有一个权值. 有两种操作: 1)      0 i j, 问节点i->节点j的路上的总权值. 2)      1 i v, 把节点i的权值改变成v. 思路: 权值在点上的树链剖分+线段树单点更新+线段树成段询问 1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <cstdio> 5 #include <vecto

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条探险航