【BZOJ 1036】树的统计Count(树链剖分)

【BZOJ 1036】树的统计Count(树链剖分)

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 12991  Solved: 5233

Description

  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成

一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

Input

  输入的第一行为一个整数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之间。

Output

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

Sample Input

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

Sample Output

4

1

2

2

10

6

5

6

5

16

树剖板子题,手生了居然在线段树挂了=。=GG……

顺发现一个小东西,查询区间的时候其实不用按链顶的深度来查。

按dfs序就行。

代码如下:

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)

using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 10000;
const int mod = 1e9+7;
const double eps = 1e-8;

struct Edge
{
    int v,next;
};

int bit[2][233333];
int head[33333];
int ttp[33333],dfn[33333],nxt[33333],pre[33333];
Edge eg[66666];
int tp,n,tim;

void Add(int u,int v)
{
    eg[tp].v = v;
    eg[tp].next = head[u];
    head[u] = tp++;
}

int dfs1(int u,int pre)
{
    int v;
    int mx = 0,id,tmp,cnt;
    id = u;
    cnt = 1;

    for(int i = head[u]; i != -1; i = eg[i].next)
    {
        v = eg[i].v;
        if(v == pre) continue;
        tmp = dfs1(v,u);
        cnt += tmp;
        //printf("%d-%d %d\n",u,v,tmp);
        if(mx < tmp)
        {
            mx = tmp;
            id = v;
        }
    }

    nxt[u] = id;
    return cnt;
}

void dfs2(int u,int pr,int bos)
{
    dfn[u] = tim++;
    pre[u] = pr;
    ttp[u] = bos;
    int v;

    if(nxt[u] == u) return;
    dfs2(nxt[u],u,bos);

    for(int i = head[u]; i != -1; i = eg[i].next)
    {
        v = eg[i].v;
        if(v == pr || v == nxt[u]) continue;
        dfs2(v,u,v);
    }
}

void Change(int root,int l,int r,int pos,int x)
{
    if(l == r)
    {
        bit[0][root] = bit[1][root] = x;
        return;
    }

    int mid = (l+r)>>1;
    if(mid >= pos) Change(root<<1,l,mid,pos,x);
    else Change(root<<1|1,mid+1,r,pos,x);
    bit[0][root] = bit[0][root<<1]+bit[0][root<<1|1];
    bit[1][root] = max(bit[1][root<<1],bit[1][root<<1|1]);
}

int Sum(int root,int l,int r,int ll,int rr)
{
    //printf("%d %d %d\n",l,r,bit[0][root]);
    if(l == ll && r == rr) return bit[0][root];

    int mid = (l+r)>>1;
    if(mid >= rr) return Sum(root<<1,l,mid,ll,rr);
    else if(mid+1 <= ll) return Sum(root<<1|1,mid+1,r,ll,rr);
    else return Sum(root<<1,l,mid,ll,mid)+Sum(root<<1|1,mid+1,r,mid+1,rr);
}

int Max(int root,int l,int r,int ll,int rr)
{
    if(l == ll && r == rr) return bit[1][root];

    int mid = (l+r)>>1;
    if(mid >= rr) return Max(root<<1,l,mid,ll,rr);
    else if(mid+1 <= ll) return Max(root<<1|1,mid+1,r,ll,rr);
    else return max(Max(root<<1,l,mid,ll,mid),Max(root<<1|1,mid+1,r,mid+1,rr));
}

void solve(char ch,int a,int b)
{
    if(ch == ‘H‘) Change(1,0,n-1,dfn[a],b);
    else if(ch == ‘M‘)
    {
        int ans = -INF;
        while(ttp[b] != ttp[a])
        {
            if(dfn[b] < dfn[a]) swap(b,a);
            //printf("%d-%d %d-%d",ttp[b],b,dfn[ttp[b]],dfn[b]);
            ans = max(ans,Max(1,0,n-1,dfn[ttp[b]],dfn[b]));
            b = pre[ttp[b]];
        }
        if(dfn[b] < dfn[a]) swap(b,a);
        if(a) ans = max(ans,Max(1,0,n-1,dfn[a],dfn[b]));
        printf("%d\n",ans);
    }
    else
    {
        int ans = 0;
        while(ttp[b] != ttp[a])
        {
            if(dfn[b] < dfn[a]) swap(b,a);
            //printf("%d-%d %d-%d\n",ttp[b],b,dfn[ttp[b]],dfn[b]);
            ans += Sum(1,0,n-1,dfn[ttp[b]],dfn[b]);
            b = pre[ttp[b]];
        }
        if(dfn[b] < dfn[a]) swap(b,a);
        if(a)
        {
            //printf("%d-%d %d-%d\n",a,b,dfn[a],dfn[b]);
            ans += Sum(1,0,n-1,dfn[a],dfn[b]);
        }
        printf("%d\n",ans);
    }
}

int main()
{
    //fread("in.in");
    //fwrite("run.out");

    int u,v,x;

    while(~scanf("%d",&n))
    {
        memset(head,-1,sizeof(head));
        tp = 0;

        for(int i = 1; i < n; ++i)
        {
            scanf("%d%d",&u,&v);
            Add(u,v);
            Add(v,u);
        }

        dfs1(1,1);
        ttp[0] = 1;
        tim = 0;
        dfs2(1,0,1);

        memset(bit,0,sizeof(bit));
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d",&x);
            //printf("%d:fa:%d dfn:%d top:%d\n",i,pre[i],dfn[i],ttp[i]);
            Change(1,0,n-1,dfn[i],x);
        }

        int m;
        char opt[6];
        int a,b;
        scanf("%d",&m);
        while(m--)
        {
            scanf("%s%d%d",opt,&a,&b);
            solve(opt[1],a,b);
        }
    }

    return 0;
}

时间: 2024-10-01 13:23:43

【BZOJ 1036】树的统计Count(树链剖分)的相关文章

HYSBZ - 1036 树的统计Count 树链剖分 求和+最大值

好水0.0 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #include<string> #define eps 1e-12 #de

BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14982  Solved: 6081[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14302  Solved: 5779[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

bzoj 1036 [ZJOI2008]树的统计Count 树链剖分模板

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 18615  Solved: 7598[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分)(线段树单点修改)

[ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14968  Solved: 6079[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I II.

BZOJ1036: [ZJOI2008]树的统计Count - 树链剖分 -

1036: [ZJOI2008]树的统计Count Description 一棵树上有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本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n – 1

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

[BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有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本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n

bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

[ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n – 1行,每行

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时... 代码如下: 1 //树链剖分 点权修改 修改单节点 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdio> 6 using namespa

bzoj 1036 树的统计Count (树链剖分+线段树)

题目大意:给你一棵树,每个点都有点权 有3种操作,修改某节点的权值,求树链上节点的权值的最大值,求树链上节点的权值和 树剖裸题,搜一个树链剖分序,用线段树维护一下即可,总时间 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <queue> 5 #define inf 0x3f3f3f3f 6 #define ll long long 7 #define N