bzoj 1036 树链剖分+线段树 裸题

HYSBZ - 1036

题意:中文题

思路:树链剖分裸题,线段树写得比较搓,(在线段树上修改节点u的时候应该修改u映射到线段树后的节点序号,这里wa了半年,真的是半年)

AC代码:

#include "iostream"
#include "string.h"
#include "stack"
#include "queue"
#include "string"
#include "vector"
#include "set"
#include "map"
#include "algorithm"
#include "stdio.h"
#include "math.h"
#define ll long long
#define bug cout<<"UUUUUUUU"<<endl;
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
const int MAX=1e5+100;
int son[MAX],siz[MAX],fa[MAX],de[MAX],top[MAX],tip[MAX];
struct Edge{
    int to;
    int next;
};
Edge e[MAX<<1];
int tot=1,cnt=1,head[MAX];
void add(int u, int v){
    e[tot].to=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
void Dfs1(int u, int f){
    siz[u]=1;
    fa[u]=f;
    de[u]=de[f]+1;
    for(int i=head[u]; i!=-1; i=e[i].next){
        int v=e[i].to;
        if(v==fa[u]) continue;
        Dfs1(v,u);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]]) son[u]=v;
    }
}
void Dfs2(int u, int tp){
    tip[u]=cnt++;
    top[u]=tp;
    if(son[u]) Dfs2(son[u],tp);
    for(int i=head[u]; i!=-1; i=e[i].next){
        int v=e[i].to;
        if(v!=fa[u]&&son[u]!=v) Dfs2(v,v);
    }
}
int w[MAX<<2],sum[MAX<<2],m[MAX];
void push_up(int rt){
    m[rt]=max(m[rt<<1],m[rt<<1|1]);
    sum[rt]=(sum[rt<<1]+sum[rt<<1|1]);
}
void Build(int rt, int l, int r){
    if(l==r){
        sum[rt]=m[rt]=w[l];
        return;
    }
    int mid=l+r>>1;
    Build(rt<<1,l,mid);
    Build(rt<<1|1,mid+1,r);
    push_up(rt);
}
void update(int rt, int L, int R, int p,int w){
    if(L==R){
        sum[rt]=m[rt]=w;
        return;
    }
    int mid=L+R>>1;
    if(p<=mid) update(rt<<1,L,mid,p,w);
    else update(rt<<1|1,mid+1,R,p,w);
    push_up(rt);
}
int query_max(int rt,int l, int r, int L, int R){
    if(l==L&&r==R) return m[rt];
    int mid=L+R>>1;
    if(r<=mid) return query_max(rt<<1,l,r,L,mid);
    else if(l>mid) return query_max(rt<<1|1,l,r,mid+1,R);
    else return max(query_max(rt<<1,l,mid,L,mid),query_max(rt<<1|1,mid+1,r,mid+1,R));
}
int query_sum(int rt, int l, int r,int L, int R){
    if(l==L&&r==R) return sum[rt];
    int mid=L+R>>1;
    if(r<=mid) return query_sum(rt<<1,l,r,L,mid);
    else if(l>mid) return query_sum(rt<<1|1,l,r,mid+1,R);
    else return query_sum(rt<<1,l,mid,L,mid)+query_sum(rt<<1|1,mid+1,r,mid+1,R);
}
void get_sum(int u,int v,int n){
    int ans=0;
    while(top[u]!=top[v]){
        if(de[top[v]]<de[top[u]]) swap(u,v);
        ans+=query_sum(1,tip[top[v]],tip[v],1,n);
        v=fa[top[v]];
    }
    if(de[u]<de[v]) swap(u,v);
    ans+=query_sum(1,tip[v],tip[u],1,n);
    printf("%d\n",ans);
}
void get_max(int u, int v,int n){
    int ans=-1<<30;
    while(top[u]!=top[v]){
        if(de[top[v]]<de[top[u]]) swap(u,v);
        ans=max(ans,query_max(1,tip[top[v]],tip[v],1,n));
        v=fa[top[v]];
    }
    if(de[u]<de[v]) swap(u,v);
    ans=max(ans,query_max(1,tip[v],tip[u],1,n));
    printf("%d\n",ans);
}
int main(){
    int n,q,a,b;
    char s[15];
    scanf("%d",&n);
    memset(head,-1,sizeof(head));
    for(int i=1; i<n; ++i){
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    Dfs1(1,1);
    Dfs2(1,1);
    for(int i=1; i<=n; ++i) scanf("%d",&w[tip[i]]);
    Build(1,1,n);
    scanf("%d",&q);
    while(q--){
        getchar();
        scanf("%s%d%d",s,&a,&b);
        if(s[1]==‘M‘) get_max(a,b,n);
        else if(s[1]==‘S‘) get_sum(a,b,n);
        else update(1,1,n,tip[a],b);
    }
   return 0;
}
时间: 2024-08-03 06:55:52

bzoj 1036 树链剖分+线段树 裸题的相关文章

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

bzoj 2157: 旅游【树链剖分+线段树】

裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio> using namespace std; const int N=200005; int n,m,h[N],cnt,de[N],va[N],fa[N],si[N],hs[N],fr[N],id[N],tot,rl[N]; char c[10]; struct qwe { int ne,no,to,va

hdu3966 树链剖分+线段树 裸题

HDU - 3966 题意:给一颗树,3种操作,Q u 查询u节点的权值,I a b c 对a到b的路径上每个点的点权增加c,D a b c 对a b 路径上所有点的点权减少c 思路:树链剖分+线段树,2个问题,第一,如果是先建树再输入点的点权,记录tip(点映射到线段树后的位置),如果先输入点权,再建树,不仅要记录tip还要记录ran(线段树上某个位置上的点对应的树上点的序号,与tip是相互映射):第二,连接起线段树和树链剖分的是get函数,区间操作才需要用到get函数,单点操作直接在线段树上

【POJ3237】Tree(树链剖分+线段树)

Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 throughN − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions

HDU 3966 Aragorn&#39;s Story (树链剖分+线段树)

题意:给你一棵树,然后有三种操作 I L R K: 把L与R的路径上的所有点权值加上K D L R K:把L与R的路径上的所有点权值减去K Q X:查询节点编号为X的权值 思路:树链剖分裸题(我还没有怎么学懂,但基本已经没有什么太大的问题,主要的问题就在于点或者边对于数据结构的映射关系是,主要没有单独手写过树链剖分,所以对这部分 没有什么体会) 我们知道树链剖分是一种将树剖为链的一种算法,其思想和dfs序差不多,但根据树链剖分的性质,我们的重链是连续的区间,这样对于重链或者重链上的点我们可以方便

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

BZOJ2243 (树链剖分+线段树)

Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. 解题分析 树链剖分+线段树. 开一个记录类型,记录某一段区间的信息.l 表示区间最左侧的颜色 , r 表示区间最右侧的颜色 , sum 表示区间中颜色段数量. 合并时判断一下左区间的右端点和有区间的左端点的颜色是否一样. 树上合并时需要用两个变量ans1,ans2来存储.ans1表示x往上走时形成的链的信息,

bzoj4304 (树链剖分+线段树)

Problem T2 (bzoj4304 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 解题分析 练手题.树链剖分+线段树. 参考程序 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #incl