• 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
    ",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
    ", sum(p[u])+a[u]);
                }
                else {
                    scanf("%d%d%d", &C1, &C2, &K);
                    if (op[0]=='D')
                        K = -K;
                    change(C1, C2, K);
                }
            }
        }
    }
  • 相关阅读:
    今天的赢在中国推迟了,给大家推荐个视频,看看什么是真正的中华武术
    赢在中国080312
    盛大(上海)诚聘软件测试人员
    jQuery入门[2]-选择器
    阿里巴巴诚信通成为《赢在中国》的实战项目,要花多少钱?--《赢在中国》(20080408)
    唐僧晒书
    用于生成网页、WAP、JS中文编码的Unicode编码工具
    jQuery入门[5]-AJAX
    中国哲学(一)
    20071212公映的《色即是空2》(sex is zero 2)字幕文件
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10040378.html
Copyright © 2020-2023  润新知