【树链剖分】[BZOJ1036][ZJOI2008]树的统计Count

来源:互联网 发布:c seo的伪静态 编辑:程序博客网 时间:2024/04/27 10:59

题目描述

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

样例输入

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

样例输出

4
1
2
2
10
6
5
6
5
16

题目分析

我们可以通过观察题目发现emoji难道这不是一个裸的树链剖分么。。。。。。每次操作复杂度O(logN)。。总复杂度O(QlogN)。。。这数据刚刚好。。写树链剖分吧,我记得树链剖分是可以用来求LCA的,就按照那个方法搞一搞就好了

代码

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 30000;const int MAXQ = 200000;struct node{    int v;    node *next;}Edges[MAXN*2+10], *ecnt=Edges, *adj[MAXN+10];int Maxson[MAXN+10], sz[MAXN+10], id[MAXN+10], idcnt, top[MAXN+10], vals[MAXN+10], Dep[MAXN+10], Fa[MAXN+10], revid[MAXN+10];void addedge(int u, int v){    ++ecnt;    ecnt->v = v;    ecnt->next = adj[u];    adj[u] = ecnt;}void dfs(int u, int fa){    sz[u]=1;    Fa[u] = fa;    Dep[u]=Dep[fa]+1;    for(node *p=adj[u];p;p=p->next){        if(p->v == fa) continue;        dfs(p->v, u);        sz[u] += sz[p->v];        if(sz[p->v] > sz[Maxson[u]])            Maxson[u] = p->v;    }}void dfs2(int u, int tp, int fa){    top[u] = tp;    revid[(id[u]=++idcnt)]=u;    if(Maxson[u]) dfs2(Maxson[u], tp, u);    for(node *p=adj[u];p;p=p->next){        if(p->v==fa||p->v==Maxson[u]) continue;        dfs2(p->v, p->v, u);    }}struct Tree{    int Max, Sum;}tree[MAXN*4+10];void push_up(int u){    tree[u].Max = max(tree[u*2].Max, tree[u*2+1].Max);    tree[u].Sum = tree[u*2].Sum + tree[u*2+1].Sum;}void Update(int u, int l, int r, int p, int v){    if(l == r){        tree[u].Max = tree[u].Sum = v;        return ;    }else{        int mid = (l + r) >> 1;        if(p<=mid)Update(u*2, l, mid, p, v);        else Update(u*2+1, mid+1, r, p, v);        push_up(u);    }}int sumq(int u, int l, int r, int ql, int qr){    if(ql <= l && r <= qr)        return tree[u].Sum;    else if(ql > r || qr < l)        return 0;    int mid = (l + r) >> 1;    if(ql > mid) return sumq(u*2+1, mid+1, r, ql, qr);    else if(qr <= mid) return sumq(u*2, l, mid, ql, qr);    return sumq(u*2, l, mid, ql, qr) + sumq(u*2+1, mid+1, r, ql, qr);}int maxq(int u, int l, int r, int ql, int qr){    if(ql <= l && r <= qr) return tree[u].Max;    int mid = (l + r) >> 1;    if(ql > mid) return maxq(u*2+1, mid+1, r, ql, qr);    else if(qr <= mid) return maxq(u*2, l, mid, ql, qr);    return max(maxq(u*2, l, mid, ql, qr), maxq(u*2+1, mid+1, r, ql, qr));}int Qsum(int l, int r){    int f1 = top[l], f2 = top[r], ret = 0;    while(f1 != f2){        if(Dep[f1] < Dep[f2]){            swap(f1, f2);            swap(l, r);        }        ret += sumq(1, 1, idcnt, id[f1], id[l]);        l = Fa[f1];        f1 = top[l];    }    if(Dep[l] > Dep[r])        swap(l, r);    return ret + sumq(1, 1, idcnt, id[l], id[r]);}int Qmax(int l, int r){    int f1 = top[l], f2 = top[r], ret = -1000000000;    while(f1 != f2){        if(Dep[f1] < Dep[f2]){            swap(f1, f2);            swap(l, r);        }        ret = max(ret, maxq(1, 1, idcnt, id[f1], id[l]));        l = Fa[f1];        f1 = top[l];    }    if(Dep[l] > Dep[r])        swap(l, r);    return max(ret, maxq(1, 1, idcnt, id[l], id[r]));}void dfs3(int u, int l, int r){    if(l == r){        tree[u].Max = tree[u].Sum = vals[revid[l]];        return ;    }    int mid = (l + r) >> 1;    dfs3(u*2, l, mid);    dfs3(u*2+1, mid+1, r);    push_up(u);}int main(){    int n, u, v;    scanf("%d", &n);    for(int i=1;i<n;i++){        scanf("%d%d", &u, &v);        addedge(u, v);        addedge(v, u);    }    dfs(1, 0);    dfs2(1, 1, 0);    for(int i=1;i<=n;i++)        scanf("%d", &vals[i]);    dfs3(1, 1, idcnt);    int q, a, b;    char ord[40];    scanf("%d", &q);    while(q--){        scanf("%s%d%d", ord, &a, &b);        if(ord[0] == 'C')            Update(1, 1, idcnt, id[a], b);        else{            if(ord[1] == 'S')                printf("%d\n", Qsum(a, b));            else                printf("%d\n", Qmax(a, b));        }    }    return 0;}
0 0
原创粉丝点击