bzoj1036--树链剖分

模板题。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define N 30001
#define INF 2147483647
vector<int>g[N];
int i,j,k,n,m,cmax[N*4],q,csum[N*4],array[N],w[N],top[N],size[N],fa[N],son[N],deep[N],w2[N],x,y,t;
char s[10];
void dfs1(int x,int f){
    int maxn;
    fa[x]=f;deep[x]=deep[fa[x]]+1;
    for(int i=0;i<g[x].size();i++)
    if(g[x][i]!=fa[x]){
        dfs1(g[x][i],x);
        size[x]+=size[g[x][i]];
        if(size[g[x][i]]>maxn){
            maxn=size[g[x][i]];
            son[x]=g[x][i];
        }
    }
    size[x]++;
}
void dfs2(int x,int tp){
    w[x]=++m;w2[m]=x;top[x]=tp;
    if(son[x])dfs2(son[x],tp);
    for(int i=0;i<g[x].size();i++)
    if(fa[x]!=g[x][i]&&g[x][i]!=son[x])dfs2(g[x][i],g[x][i]);
}
void build(int node,int l,int r){
    if(l==r){
        cmax[node]=csum[node]=array[w2[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(node<<1,l,mid);
    build(node<<1|1,mid+1,r);
    cmax[node]=max(cmax[node<<1],cmax[node<<1|1]);
    csum[node]=csum[node<<1]+csum[node<<1|1];
}
void update(int node,int l,int r,int x,int t){
    if(l==r){
        csum[node]=cmax[node]=t;
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=x)update(node<<1,l,mid,x,t);else update(node<<1|1,mid+1,r,x,t);
    cmax[node]=max(cmax[node<<1],cmax[node<<1|1]);
    csum[node]=csum[node<<1]+csum[node<<1|1];
}
int query_sum(int node,int l,int r,int L,int R){
    if(l>R||r<L)return 0;
    if(l>=L&&r<=R)return csum[node];
    int mid=(l+r)>>1;
    return query_sum(node<<1,l,mid,L,R)+query_sum(node<<1|1,mid+1,r,L,R);
}
int query_max(int node,int l,int r,int L,int R){
    if(l>R||r<L)return -INF;
    if(l>=L&&r<=R)return cmax[node];
    int mid=(l+r)>>1;
    return max(query_max(node<<1,l,mid,L,R),query_max(node<<1|1,mid+1,r,L,R));
}
int query_tree_sum(int u,int v){
    int f1=top[u],f2=top[v],ans=0;
    while(f1!=f2)
    if(deep[f1]>=deep[f2]){
        ans+=query_sum(1,1,m,w[f1],w[u]);
        u=fa[f1];
        f1=top[u];
    }else{
        ans+=query_sum(1,1,m,w[f2],w[v]);
        v=fa[f2];
        f2=top[v];
    }
    if(w[u]>w[v])ans+=query_sum(1,1,m,w[v],w[u]);else ans+=query_sum(1,1,m,w[u],w[v]);
    return ans;
}
int query_tree_max(int u,int v){
    int f1=top[u],f2=top[v],ans=-INF;
    while(f1!=f2)
    if(deep[f1]>=deep[f2]){
        ans=max(ans,query_max(1,1,m,w[f1],w[u]));
        u=fa[f1];
        f1=top[u];
    }else{
        ans=max(ans,query_max(1,1,m,w[f2],w[v]));
        v=fa[f2];
        f2=top[v];
    }
    if(w[u]>w[v])ans=max(ans,query_max(1,1,m,w[v],w[u]));else ans=max(ans,query_max(1,1,m,w[u],w[v]));
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(i=1;i<=n;i++)scanf("%d",&array[i]);
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,m);
    scanf("%d",&q);
    for(i=1;i<=q;i++){
        scanf("%s%d%d",s,&x,&y);
        if(s[0]==‘C‘)update(1,1,m,w[x],y);
        else if(s[1]==‘S‘)printf("%d\n",query_tree_sum(x,y));else printf("%d\n",query_tree_max(x,y));
    }
    return 0;
}

bzoj1036

时间: 2024-11-23 07:47:38

bzoj1036--树链剖分的相关文章

Bzoj1036 树链剖分基础题

树链剖分的基础题 因为复习到了这个部分突然发现竟然没有题解所以现在补一个.. 一些基础的东西... 重儿子:siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子. 轻儿子:v的其它子节点. 重边:点v与其重儿子的连边. 轻边:点v与其轻儿子的连边. 重链:由重边连成的路径. 轻链:轻边. 然后简单的用两次dfs计算出每个节点的father,deep,size, son,w,top 其他简单的就不说了 w表示的是当前节点与其付清节点的连边在线段树中的位置 top表示的是当前节点所在的链的

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

题意:一棵树上有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本身 1<=n<=30000,0<=q<=200000:中途操作中保证每个节点的权值w在-30000到30000之间. 思路:树链

【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

[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 树的统计(树链剖分+线段树)

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

【BZOJ1036】【ZJOI2008】树的统计Count 树链剖分裸题

题解:裸的,没什么好说的. 树链剖分不会的先理解一下重链轻链,然后直接扒我代码理解就行了. 贴代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 30100 #define inf 0x3f3f3f3f using namespace std; struct KSD { int u,v,next; }e[N<<1];

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 – 1行,每行2个整数a和b,表示节点a和节点b之间有一条

bzoj1036 count 树链剖分或LCT

这道题很久以前用树链剖分写的,最近在学LCT ,就用LCT再写了一遍,也有一些收获. 因为这道题点权可以是负数,所以在update时就要注意一下,因为平时我的0节点表示空,它的点权为0,这样可以处理点权为非负求最大值和求和的情况(即不用特判某个点是否有左右儿子,直接更新就行了),但这道题就不行(求和要求它为0,求最大值要求它为-oo).所以就必须特判~~~~ 综上:若0号节点存在一个不可能成为答案(在求最大值时是-oo,求最小值时是+oo)或对答案没有贡献的值(在求和时是0)时,初始化时将0节点