BZOJ1036 树的统计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行,每行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


代码

感谢wfwbz的指导

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<vector>
#define R0(i,n) for(register int i=0;i<n;++i)
#define R1(i,n) for(register int i=1;i<=n;++i)
#define cl(x,c) memset(x,c,sizeof x)
#define INF 0x3f3f3f3f
#define mn 30010

using namespace std;
typedef long long ll;
template <class T> inline void read(T&x){
    bool f = false; char ch;
    for (ch = getchar(); ch <= 32; ch = getchar());
    if (ch == ‘-‘) f = true, ch = getchar();
    for (x = 0; ch > 32; ch = getchar()) x = x * 10 + ch - ‘0‘;
    if (f) x = -x;
}
template <class T> inline void write(T x){
    if (x < 0) putchar(‘-‘), x = -x;
    if (x < 10)
        putchar(x + ‘0‘);
    else
        write(x / 10), putchar(x % 10 + ‘0‘);
}
template <class T> inline void writeln(T x){
    write(x);puts("");
}
void setIO(string t){
string a=t+".in",b=t+".out";
freopen(a.c_str(),"r",stdin);
freopen(b.c_str(),"w",stdout);
}
//数据
int _[mn],__[mn],n,m; 

//线段树
#define lc      k<<1
#define rc      k<<1|1
#define M       ((l+r)>>1)
#define All     1,1,n
#define lson lc,l,M
#define rson rc,M+1,r

int sumv[mn<<2], maxv[mn<<2];

void push_up(int k){
    sumv[k] = sumv[lc] + sumv[rc];
    maxv[k] = max(maxv[lc], maxv[rc]);
}

void build(int k,int l,int r){
    if(l==r)sumv[k]=maxv[k]=__[l];
    else build(lson),build(rson),push_up(k);
}

int _l, _r,_a,_b;//全局变量减少传的参数
int query_sum(int k,int l,int r){
    if(_l<=l&&r<=_r)return sumv[k];
    int ret = 0;
    if(_l<=M)ret+=query_sum(lson);
    if(M<_r) ret+=query_sum(rson);
    return ret;
}
int query_max(int k,int l,int r){
    if(_l<=l&&r<=_r)return maxv[k];
    int ret=-INF;
    if(_l<=M) ret=max(ret,query_max(lson));
    if(M <_r) ret=max(ret,query_max(rson));
    return ret;
}
void update(int k,int l,int r) {
    if(l==_a &&r==_a)sumv[k]=maxv[k]=_b;
    else {
        if(_a<=M) update(lson);
        else update(rson);
        push_up(k);
    }
}

//重链剖分
int dep[mn],fa[mn],size[mn],tid[mn],top[mn],son[mn];
/*
dep深度
fa父亲节点
size以i为根的子树节点个数
tid新编号
top祖先
son孩子节点
这一块还不太明白如果有错欢迎指正
*/
 vector<int>ch[mn];
void f_h_e(int x,int father,int depth){//找重边
    dep[x]=depth,fa[x]=father,size[x]=1;
    int maxsize=0;
    R0(i,ch[x].size()){
        int child=ch[x][i];
        if(child!=father){
            f_h_e(child,x,depth+1);
            size[x]+=size[child];
            if(size[child]>maxsize)maxsize=size[child],son[x]=child;
        }
    }
}
int label;//新编号用

void c_h_e(int x,int anc){//连重链
    __[tid[x]=++label]=_[x];//按新编号排列数据
    top[x]=anc;//top 重链祖先
    if(son[x]){
        c_h_e(son[x],anc);
        R0(i,ch[x].size()){
            int child=ch[x][i];
            if(child!=fa[x]&&child!=son[x])c_h_e(child,child);//轻的自己连自己
        }
    }
}

//修改
//单点修改直接走数据结构

//询问
int ask_sum(int x,int y){
    int ret=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        _l=tid[top[x]],_r=tid[x],ret+=query_sum(All);
        x=fa[top[x]];
    }//不在同一条重链上
    if(dep[x]>dep[y])swap(x,y);
    _l=tid[x],_r=tid[y],ret+=query_sum(All);
    return ret;//到达同一条重链
}
int ask_max(int x,int y){
    int ret=-INF;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        _l=tid[top[x]],_r=tid[x],ret=max(ret,query_max(All));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    _l=tid[x],_r=tid[y],ret=max(ret,query_max(All));
    return ret;
} //同上

int main(){
    read(n);int a,b;
    R1(i,n-1){
        read(a),read(b);
        ch[a].push_back(b);
        ch[b].push_back(a);
    }
    R1(i,n)read(_[i]);

    //
    cl(maxv,-0x3f);
    f_h_e(1,1,1);
    c_h_e(1,1);
    build(All);
    read(m);
    char cmd[7];
    R0(i,m){
        scanf("%s",cmd);
        read(a),read(b);
        switch(cmd[1]){
            case‘S‘:{writeln(ask_sum(a,b));break;}
            case‘M‘:{writeln(ask_max(a,b));break;}
            case‘H‘:{_a=tid[a],_b=b;update(All);break;}//这里_a要用新标号
        }
    }
    return 0;
}
时间: 2024-07-28 23:39:19

BZOJ1036 树的统计Count的相关文章

[ZJOI2008][BZOJ1036] 树的统计count

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

BZOJ1036 树的统计Count(同时求sum max)

#include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <map> #include <set> #include <vector> #include <cstdio> using namespace std; const int N=30010; s

bzoj1036 树的统计Count 【树链剖分+线段树】

#include<bits/stdc++.h> using namespace std; const long long inf=1<<30; const int N=40000+10; typedef long long ll; struct { int a,b; }g[N]; struct { int l,r; ll sum,mx; }tree[4*N]; vector<int>v[N]; int n,fa[N],dep[N],sz[N],son[N],w[N],t

【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 解题报告|树链剖分

树链剖分 简单来说就是数据结构在树上的应用.常用的为线段树splay等.(可现在splay还不会敲囧) 重链剖分: 将树上的边分成轻链和重链. 重边为每个节点到它子树最大的儿子的边,其余为轻边. 设(u,v)为轻边,则size(v)<=size(u)/2 (一旦大于了那必然是重边) 也就是一条路径上每增加一条轻边节点个数就会减少一半以上,那么显然根到任意一个节点路径上的轻边条数一定不会超过log(n)(不然节点就没了啊23333) 重链定义为一条极长的连续的且全由重边构成的链. 容易看出重链两两

bzoj1036: [ZJOI2008]树的统计Count(树链剖分+线段树维护)

bzoj1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MB 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的路径上的

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】

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

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行,每行