[JSOI2008][BZOJ1036] 树的统计 - 树链剖分

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 & Output

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”的形式给出。

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

Output

4
1
2
2
10
6
5
6
5
16

Solution

资瓷单点修改,路径查询最大值,路径查询点权和,比较裸的树剖。
怕不是常数比较大只过了洛谷(逃
Code:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <string>

using std::min;
using std::max;
using std::swap;
using std::isdigit;
using std::memset;
using std::string;
using std::cin;
using std::cout;
using std::endl;
using std::ios;

const int maxn = 30005;

struct edge{
    int to,nxt;
}e[maxn<<1];
struct node{
    int w,mx,tag;
    node()
    {
        mx = w = tag = 0;
    }
}tr[maxn << 2];
int lnk[maxn],edgenum;
int top[maxn],size[maxn],dep[maxn],son[maxn],f[maxn],dfn[maxn],dfn2[maxn];
int cnt;
int w[maxn],v[maxn],n,m,q;

void add(int bgn,int end)
{
    e[++edgenum].to = end;
    e[edgenum].nxt = lnk[bgn];
    lnk[bgn] = edgenum;
}
void dfs(int x,int fa,int d)
{
    size[x] = 1;
    f[x] = fa;
    dep[x] = d;
    for(int p = lnk[x]; p; p = e[p].nxt)
    {
        int y = e[p].to;
        if(y == fa)continue;
        dfs(y, x, d + 1);
        size[x] += size[y];
        if(size[y] > size[son[x]]) son[x] = y;
    }
}
void dfs2(int x,int init)
{
    dfn[x] = ++cnt;
    w[cnt] = v[x];
    top[x] = init;
    if(!son[x])return;
    dfs2(son[x],init);
    for(int p = lnk[x]; p; p = e[p].nxt)
    {
        int y = e[p].to;
        if(y == f[x]||y == son[x])continue;
        dfs2(y,y);
    }
}
void build(int cur,int l,int r)
{
    if(l == r)
    {
        tr[cur].w = w[l];
        tr[cur].mx = w[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(cur<<1,l,mid);
    build(cur<<1|1,mid + 1,r);
    tr[cur].w = tr[cur<<1].w + tr[cur<<1|1].w;
    tr[cur].mx = max(tr[cur<<1].mx,tr[cur<<1|1].mx);
}
int querys(int cur,int l,int r,int L,int R)
{
    int res = 0;
    if(L <= l && R >= r)
    {
        res += tr[cur].w;
        return res;
    }
    int mid = (l+r)>>1;
    if(L<=mid) res += querys(cur<<1,l,mid,L,R);
    if(R>mid) res += querys(cur<<1|1,mid+1,r,L,R);
    return res;
}
int queryx(int cur,int l,int r,int L,int R)
{
    int res = -214748;
    if(L <= l && R >= r)
        return tr[cur].mx;
    int mid = (l+r)>>1;
    if(L<=mid) res = max(res, queryx(cur<<1,l,mid,L,R));
    if(R>mid) res = max(res, queryx(cur<<1|1,mid+1,r,L,R));
    return res;
}
void pupdate(int cur,int l,int r,int p,int c)
{
    if(l == r)
    {
        tr[cur].w = c;
        tr[cur].mx = c;
        return;
    }
    else{
        int mid = (l+r)>>1;
        if(p <= mid)pupdate(cur<<1,l,mid,p,c);
        else pupdate(cur<<1|1,mid+1,r,p,c);
        tr[cur].w = tr[cur<<1].w + tr[cur<<1|1].w;
        tr[cur].mx = max(tr[cur<<1].mx,tr[cur<<1|1].mx);
    }
}
//---------------------------
int queryts(int x,int y)
{
    int ans = 0;
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]])swap(x,y);
        ans += querys(1,1,n,dfn[top[x]],dfn[x]);
        x = f[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans += querys(1,1,n,dfn[x],dfn[y]);
    return ans;
}
int querytx(int x,int y)
{
    int ans = -214748;
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]])swap(x,y);
        ans = max(ans, queryx(1,1,n,dfn[top[x]],dfn[x]));
        x = f[top[x]];
    }
    if(dep[x] > dep[y])swap(x,y);
    ans = max(ans, queryx(1,1,n,dfn[x],dfn[y]));
    return ans;
}

int main()
{
    ios::sync_with_stdio(false);
    string s;
    int x,y;
    cin >> n;
    for(int i = 1; i < n; ++i)
    {
        cin >> x >> y;
        add(x,y);
        add(y,x);
    }
    for(int i = 1; i <= n; ++i)
        cin >> v[i];
    dfs(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    cin >> q;
    for(int i = 1; i <= q; ++i)
    {
        cin >> s;
        if(s[0] == 'C')
        {
            cin >> x >> y;
            pupdate(1,1,n,dfn[x],y);
        }
        else if(s[0] == 'Q' && s[1] == 'M')
        {
            cin >> x >> y;
            cout << querytx(x,y) << endl;
        }
        else
        {
            cin >> x >> y;
            cout << queryts(x,y) << endl;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/nishikino-curtis/p/9047737.html

时间: 2024-11-18 19:07:45

[JSOI2008][BZOJ1036] 树的统计 - 树链剖分的相关文章

kyeremal-bzoj1036[ZJOI2008]-树的统计count-树链剖分

bzoj1036[ZJOI2008]-树的统计count 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 7567  Solved: 3109 [Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QM

树的统计Count---树链剖分

NEFU专项训练十和十一——树链剖分 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行,每行2个整

zjoi 2008 树的统计——树链剖分

比较基础的一道树链剖分的题 大概还是得说说思路 树链剖分是将树剖成很多条链,比较常见的剖法是按儿子的size来剖分,剖分完后对于这课树的询问用线段树维护--比如求路径和的话--随着他们各自的链向上走,直至他们在同一条链上为止.比较像lca的方法,只不过这里是按链为单位,而且隔壁的SymenYang说可以用树链剖分做lca..吓哭 然后说说惨痛的调题经历:边表一定要开够啊! 不是n-1 而是2*(n-1)啊! 然后写变量时原始值和映射值要搞清楚啊! 不要搞错了! 还有就是下次求最小值一定看清下界是

BZOJ 1036 树的统计-树链剖分

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

【BZOJ 1036】【ZJOI 2008】树的统计 树链剖分模板题

sth神犇的模板: //bzoj1036 题目:一个n个点的树每个点有一个权值,支持修改单点权值,求某两点路径上的点权和或最大点权. #include <cstdio> using namespace std; int pos[30001],f[30001],up[30001],son[30001],size[30001],a[80001],next[80001],last[30001],sum[100001],max[100001];//pos是指某点在线段树中的位置:f是父节点:up是所在

luoguP2590 [ZJOI2008]树的统计 [树链剖分] [TLE的LCT]

题目描述 一棵树上有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之

[ZJOI2008]树的统计 (树链剖分)

题目描述 一棵树上有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之

【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)-树链剖分

Problem 树的统计 题目大意 一棵树上有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本身 So Lazy No Solution 裸的树链剖分,题解一搜一大把.就连这个都炸了几次.我太菜了... AC