树链剖分

基本思想以及操作

第一遍dfs求出树每个结点的深度deep[x],其为根的子树大小size[x]
以及祖先的信息fa[x][i]表示x往上距离为2^i的祖先
第二遍dfs
根节点为起点,向下拓展构建重链
选择最大的一个子树的根继承当前重链
其余节点,都以该节点为起点向下重新拉一条重链
ž给每个结点分配一个位置编号,每条重链就相当于一段区间,用数据结构去维护。
把所有的重链首尾相接,放到同一个数据结构上,然后维护这一个整体即可
修改操作
1、单独修改一个点的权值
根据其编号直接在数据结构中修改就行了。
2、修改点u和点v的路径上的权值
(1)若u和v在同一条重链上
直接用数据结构修改pos[u]至pos[v]间的值。
(2)若u和v不在同一条重链上
一边进行修改,一边将u和v往同一条重链上靠,然后就变成了情况(1)。

几道板子题

ZJOI2008树的统计

http://www.lydsy.com/JudgeOnline/problem.php?id=1036
这道题要注意的是输入字符串一定要用scanf啊!!!!!!

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define lson (x << 1)
#define rson (x << 1 | 1)
#define ll long long
#define INF 2147483640
using namespace std;
const int maxn = 200000 + 100;
int n,x,y,tt,q,u,v,t,cnt;
int head[maxn],nxt[2*maxn],to[2*maxn];
int a[maxn],son[maxn],fa[maxn],top[maxn],dep[maxn],sz[maxn],dfn[maxn];
char s[20];
struct segtree {
    int max,sum;
} tr[4*maxn];
inline int gi() {
    int x = 0,o = 1;
    char ch = getchar();
    while(ch != '-'&&(ch < '0'||ch > '9'))  ch = getchar();
    if(ch == '-')  ch = getchar(),o = -1;
    while(ch >= '0'&&ch <= '9')  x = x*10+ch-'0',ch = getchar();
    return x*o;
}

inline void dfs1(int x,int d) {
    dep[x] = d,sz[x] = 1;
    for(int i = head[x]; i ; i = nxt[i]) {
        if(!dep[to[i]]) {
            dfs1(to[i],d+1),sz[x] += sz[to[i]],fa[to[i]] = x;
            if(!son[x]|| sz[to[i]] > sz[son[x]])     son[x] = to[i];
        }
    }
}

inline void dfs2(int x,int f) {
    dfn[x] = ++cnt,top[x] = f;
    if(son[x] )  dfs2(son[x],f);
    for(int i = head[x]; i  ; i = nxt[i])
        if(to[i] != son[x]&&to[i] != fa[x])  dfs2(to[i],to[i]);
}

inline void build(int x,int l,int r) {
    tr[x].max = -INF,tr[x].sum = 0;
    if(l == r)  return ;
    int mid = (l+r) >> 1;
    build(lson,l,mid),build(rson,mid+1,r);
}

inline void update(int x,int l,int r,int num,int p) {
    if(l == r) {
        tr[x].max = p , tr[x].sum = p;
        return ;
    }
    int mid = (l+r) >> 1;
    if(num <= mid) update(lson,l,mid,num,p);
    if(num > mid) update(rson,mid+1,r,num,p);
    tr[x].max = max(tr[lson].max,tr[rson].max);
    tr[x].sum = tr[lson].sum + tr[rson].sum;
}

inline int query_sum(int x,int l,int r,int xl,int xr) {
    if(xl <= l&&r <= xr)  return tr[x].sum;
    int mid = (l+r) >> 1;
    ll ret = 0;
    if(xl <= mid)  ret += query_sum(lson,l,mid,xl,xr);
    if(xr > mid)  ret += query_sum(rson,mid+1,r,xl,xr);
    return ret;
}

inline int query_max(int x,int l,int r,int xl,int xr) {
    if(xl <= l&&r <= xr)  return tr[x].max;
    int mid = (l+r) >> 1;
    if(xr <= mid)  return query_max(lson,l,mid,xl,xr);
    else if(xl > mid)  return query_max(rson,mid+1,r,xl,xr);
    else
    return max(query_max(lson,l,mid,xl,mid),query_max(rson,mid+1,r,mid+1,xr));
}

inline int work_max(int x,int y) {
    int ans = -INF;
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]])  swap(x,y);
        ans = max(ans,query_max(1,1,cnt,dfn[top[x]],dfn[x]));
        x = fa[top[x]];
    }
    if(dep[x] > dep[y])  swap(x,y);
    ans = max(ans,query_max(1,1,cnt,dfn[x],dfn[y]));
    return ans;
}

inline int work_sum(int x,int y) {
    int ans = 0;
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]])  swap(x,y);
        ans += query_sum(1,1,cnt,dfn[top[x]],dfn[x]);
        x = fa[top[x]];
    }
    if(dep[x] > dep[y])  swap(x,y);
    ans += query_sum(1,1,cnt,dfn[x],dfn[y]);
    return ans;
}

int main() {
    n = gi();
    for(int i = 1; i < n; i++) {
        x = gi(),y = gi();
        to[++tt] = y,nxt[tt] = head[x],head[x] = tt;
        to[++tt] = x,nxt[tt] = head[y],head[y] = tt;
    }
    for(int i = 1; i <= n; i++)   a[i] = gi();
    dfs1(1,1),dfs2(1,1);
    build(1,1,cnt);
    for(int i = 1; i <= n; i++)  update(1,1,cnt,dfn[i],a[i]);
    //初始化赋初值应放在dfs后面!!!
    q = gi();
    for(int i = 1; i <= q; i++) {
        scanf("%s", s);
        if(s[1] == 'H')
        u = gi(),t = gi(),update(1,1,cnt,dfn[u],t);
        else if(s[1] == 'S') 
        u = gi(),v = gi(),printf("%d\n",work_sum(u,v));
        else if(s[1] == 'M') 
        u = gi(),v = gi(),printf("%d\n",work_max(u,v));
    }
    return 0;
}

HAOI2015树上操作

http://www.lydsy.com/JudgeOnline/problem.php?id=4034

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson (x << 1)
#define rson (x << 1 | 1)
#define ll long long
using namespace std;
const int maxn = 100005;
int n,m,x,y,tt,flag,cnt = 0;
int nxt[6*maxn],to[maxn*6],head[maxn*6];
int a[maxn],dfn[maxn],top[maxn],son[maxn],dep[maxn],sz[maxn],endd[maxn],fa[maxn];
ll lazy[8*maxn],sum[8*maxn];
inline int gi(){
    int x = 0,o = 1;
    char ch = getchar();
    while(ch != '-'&&(ch < '0'||ch > '9'))   ch = getchar();
    if(ch == '-')  ch = getchar(),o = -1;
    while(ch >= '0'&&ch <= '9')  x = 10*x+ch-'0',ch = getchar();
    return x*o;
}

inline void dfs1(int x,int d){
    dep[x] = d,sz[x] = 1;
    for(int i = head[x]; i ; i = nxt[i]){
        if(!dep[to[i]]){
            dfs1(to[i],d+1),sz[x] += sz[to[i]],fa[to[i]] = x;
            if(sz[to[i]] > sz[son[x]])  son[x] = to[i]; 
        }
    }
}

inline void dfs2(int x,int f){
    dfn[x] = ++cnt,top[x] = f;
    if(son[x])  dfs2(son[x],f);
    for(int i = head[x]; i ; i = nxt[i])
       if(to[i] != son[x]&&to[i] != fa[x])
          dfs2(to[i],to[i]);
    endd[x] = cnt;
}

inline void pushup(int x){
    sum[x] = sum[lson] + sum[rson];
}

inline void pushdown(int x,int l,int r){
    if(lazy[x]){
        lazy[lson] += lazy[x];
        lazy[rson] += lazy[x];
        int mid = (l+r) >> 1;
        sum[lson] += (ll)lazy[x] * (mid - l + 1);
        sum[rson] += (ll)lazy[x] * (r - mid);
        lazy[x] = 0;
    }
}

inline void update(int x,int l,int r,int xl,int xr,int p){
    pushdown(x,l,r);
    if(xl <= l&&r <= xr){
        sum[x] += (ll)p*(r-l+1);
        lazy[x] = p;
        return ;
    }
    int mid = (l + r) >> 1;
    if(xl <= mid)  update(lson,l,mid,xl,xr,p);
    if(xr > mid)  update(rson,mid+1,r,xl,xr,p);
    pushup(x);
}

inline ll query(int x,int l,int r,int xl,int xr){
    pushdown(x,l,r);
    if(xl <= l&&r <= xr)
       return sum[x];
    int mid = (l + r) >> 1;
    ll ans = 0;
    if(xl <= mid)  ans += query(lson,l,mid,xl,xr);
    if(xr > mid)  ans += query(rson,mid+1,r,xl,xr);
    return ans;
}

inline ll solvequery(int x){
    ll ans = 0;
    while(top[x] != 1){
        ans += query(1,1,n,dfn[top[x]],dfn[x]);
        x = fa[top[x]];
    }
    ans += query(1,1,n,1,dfn[x]);
    return ans;
}

int main()
{
    n = gi(),m = gi();
    for(int i = 1; i <= n;i++)
       a[i] = gi();
    for(int i = 1;i < n;i++){
        x = gi(),y = gi();
        nxt[++tt] = head[x],head[x] = tt,to[tt] = y;
        nxt[++tt] = head[y],head[y] = tt,to[tt] = x;
    }
    dfs1(1,1),dfs2(1,1);
    for(int i = 1;i <= n;i++) 
       update(1,1,n,dfn[i],dfn[i],a[i]);
    for(int i = 1;i <= m;i++){
        flag = gi();
        if(flag == 1)  x = gi(),y = gi(), update(1,1,n,dfn[x],dfn[x],y);
        if(flag == 2)  x = gi(),y = gi(), update(1,1,n,dfn[x],endd[x],y);
        if(flag == 3)  x = gi(),printf("%lld\n",solvequery(x));
    }
    return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值