hdu3966 树链剖分点权模板+线段树区间更新/树状数组区间更新单点查询

点权树的模板题,另外发现树状数组也是可以区间更新的。。

注意在对链进行操作时方向不要搞错

线段树版本

#include<bits/stdc++.h>
using namespace std;
#define maxn 50005
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
struct Edge{int to,next;}edge[maxn<<2];
int a[maxn],head[maxn],tot;
int deep[maxn],fa[maxn],son[maxn],num[maxn];
int top[maxn],fp[maxn],p[maxn],pos; 
inline void addedge(int u,int v){edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;}
void dfs1(int u,int pre,int dep){
    fa[u]=pre;deep[u]=dep;num[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(v==pre) continue;
        dfs1(v,u,dep+1);
        num[u]+=num[v];
        if(son[u]==-1 || num[son[u]]<num[v]) son[u]=v;
    }
}
void getpos(int u,int sp){
    top[u]=sp;p[u]=pos++;fp[p[u]]=u;
    if(son[u]==-1) return;
    getpos(son[u],sp);
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(v!=fa[u] && v!=son[u]) getpos(v,v);
    }
}

int seg[maxn<<2];
void build(int l,int r,int rt){
    seg[rt]=0;
    if(l==r) {seg[rt]=a[fp[l]];return;}//注意这里,线段树上坐标为i的点权值是第i个被访问到的点的权值 
    int m=l+r>>1;
    build(lson);build(rson);
}
inline void pushdown(int rt){
    if(seg[rt]) {
        seg[rt<<1]+=seg[rt];
        seg[rt<<1|1]+=seg[rt];
        seg[rt]=0;
    }
}
void update(int L,int R,int c,int l,int r,int rt){
    if(L<=l && R>=r){seg[rt]+=c;return;}
    pushdown(rt);
    int m=l+r>>1;
    if(L<=m) update(L,R,c,lson);
    if(R>m) update(L,R,c,rson);
}
int query(int pos,int l,int r,int rt){
    if(l==r) return seg[rt];
    pushdown(rt);
    int m=l+r>>1;
    if(pos<=m) return query(pos,lson);
    else return query(pos,rson);
}
void change(int u,int v,int c){
    int f1=top[u],f2=top[v];
    while(f1!=f2){
        if(deep[f1]<deep[f2]){swap(u,v);swap(f1,f2);}
        update(p[f1],p[u],c,1,pos,1);
        u=fa[f1];f1=top[u];
    }
    if(deep[u]>deep[v]) swap(u,v);
    update(p[u],p[v],c,1,pos,1);
}
void init(){
    tot=pos=0;pos=1;
    memset(head,-1,sizeof head);
    memset(son,-1,sizeof son);
}
int main(){
    int n,m,q,u,v,k;
    while(scanf("%d%d%d",&n,&m,&q)==3){
        init();
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=m;i++){scanf("%d%d",&u,&v);addedge(u,v);addedge(v,u);}
        dfs1(1,0,0);getpos(1,1);build(1,pos,1);
        char op[2];
        while(q--){
            scanf("%s",op);
            if(op[0]=='I') {scanf("%d%d%d",&u,&v,&k);change(u,v,k);}
            else if(op[0]=='D'){scanf("%d%d%d",&u,&v,&k);change(u,v,-k);}
            else {scanf("%d",&u);printf("%d\n",query(p[u],1,pos,1));}
        } 
    }
}

树状数组版本。。果然还是树状数组快一点啊

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define MAXN 50010
using namespace std;
struct Edge{
    int to, next;
}edge[MAXN*2];
int head[MAXN], tot;
int deep[MAXN];
int fa[MAXN];
int son[MAXN];
int p[MAXN];
int fp[MAXN];
int top[MAXN];
int num[MAXN];
int pos;
int c[MAXN], n;//树状数组的 
void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
    pos=1;//树状数组,编号从1开始 
    memset(son,-1,sizeof(son));
    memset(c,0,sizeof(c));
}
void addedge(int u,int v)
{
    edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;
}
void dfs1(int u, int pre, int d){
    deep[u] = d;
    fa[u] = pre;
    num[u] = 0;
    for(int i = head[u]; i != -1; i = edge[i].next){
        int v = edge[i].to;
        if (v != pre){//v不能是父节点 
            dfs1(v, u, d+1);
            num[u] += num[v];
            if (son[u]==-1||num[v]>num[son[u]])
                son[u] = v;
        }
    }
}
void getpos(int u, int sp){
    top[u] = sp;
    p[u] = pos++;
    fp[p[u]] = u;
    if (son[u] == -1)
        return;
    getpos(son[u], sp);
    for(int i = head[u]; i != -1; i = edge[i].next){
        int v = edge[i].to;
        if (v != fa[u] && v != son[u])
            getpos(v, v);
    }
} 

//树状数组
int lowbit(int i){
    return i&(-i);
} 
int sum(int i){
    int s = 0;
    while(i<=n){
        s += c[i];
        i +=lowbit(i);
    }
    return s;
}
void add(int i, int val){
    while(i>0){
        c[i]+=val;
        i-=lowbit(i);
    }
}
void change(int u, int v, int val){
    int f1 = top[u], f2 = top[v];
    while(f1 != f2){
        if (deep[f1]<deep[f2]){
            swap(f1, f2);
            swap(u, v);
        }
        add(p[u], val);//树状数组的区间更新原理 
        add(p[f1]-1, -val);//这儿得减去一个东西 
        u = fa[f1];
        f1 = top[u];
    }
    if(deep[u]>deep[v])
        swap(u,v);//默认u是v的祖先 
    add(p[u]-1, -val);
    add(p[v], val); 
}
int a[MAXN];
int main(){
    int M, P;
    while(~scanf("%d%d%d", &n, &M, &P)){
        int u, v;
        int C1, C2, K;
        char op[2];
        init();
        for(int i = 1; i<=n; i++)
            scanf("%d", &a[i]);
        while(M--){
            scanf("%d%d", &u, &v);
            addedge(u, v);
            addedge(v, u);
        }
        dfs1(1, 0, 0);
        getpos(1, 1);
        while(P--){
            scanf("%s", op);
            if (op[0]=='Q'){
                scanf("%d", &u);
                printf("%d\n", sum(p[u])+a[u]);
            }
            else {
                scanf("%d%d%d", &C1, &C2, &K);
                if (op[0]=='D')
                    K = -K;
                change(C1, C2, K);
            }
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/10040378.html