树链剖分(hdu3966)

题意:
多组数据。
n个兵营,m条道路,q个操作。
“I”:给C1和C2道路上的所有兵营都增加K个兵;
“D”:给C1和C2道路上的所有兵营都减少K个兵;
“Q”:查询第K个兵营的人。

真的好不容易,终于把这个程序给调过了。
题目<—
下面来讲述一下树链剖分;
至于dfs1和dfs2,就看这个神犇的博客<传送门>
下面由我来讲述一下用线段树来维护这道题.
change函数:
1.当他们不在同一重链上时,将不在同一重链的点移到自己重链的重儿子的父亲去,(当然一边提升,还要一边进行维护)在向上继续进行提升,直到他们在同一重链中。
2.当他们在同一重链中时,这就好办了,直接维护这两个点在重链位置中形成的区间(在对应的数据结构 ( 本题是线段树 ))。

/*
size[]数组,用来保存以x为根的子树节点个数
top[]数组,用来保存当前节点的所在链的顶端节点
son[]数组,用来保存重儿子
dep[]数组,用来保存当前节点的深度
fa[]数组,用来保存当前节点的父亲
tid[]数组,用来保存树中每个节点剖分后的新编号
rank[]数组,用来保存当前节点在线段树中的位置
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define For(aa,bb,cc) for(int aa=bb;aa<=cc;++aa)
#define ak(aa) memset(aa,0,sizeof(aa))
#define begin Begin 
#define to To
#define next Next 
#define rank Rank
#define size Size
#define lr node<<1
#define rr node<<1|1
using namespace std;
const int maxn=50010;
int n,m,q,sum;
int begin[maxn<<1],to[maxn<<1],next[maxn<<1],e;
int a[maxn];
int dep[maxn<<1],top[maxn<<1],rank[maxn<<1],son[maxn<<1],fa[maxn<<1],tid[maxn<<1],size[maxn<<1];
int lazy[maxn<<2],tree[maxn<<2];

struct tree_chain_partition{
    void add(int x,int y){
        to[++e]=y,next[e]=begin[x],begin[x]=e;
        to[++e]=x,next[e]=begin[y],begin[y]=e;
    }

    void dfs1(int node,int father,int d){
        dep[node]=d;
        fa[node]=father;
        size[node]=1;
        for(int i=begin[node];i;i=next[i]){
            int u=to[i];
            if(u!=father){//无向图处理
                dfs1(u,node,d+1);
                size[node]+=size[u];
                /*记录重儿子*/
                if(son[node]==-1 || size[u]>size[son[node]]) son[node]=u;
            }
        }
    }

    void dfs2(int node,int t){
        top[node]=t;
        tid[node]=++sum;
        rank[tid[node]]=node;
        if(son[node]==-1) return ;
        /*便利重链*/
        dfs2(son[node],t);
        for(int i=begin[node];i;i=next[i]){
            int u=to[i];
            /*轻链*/
            if(u!=son[node] && u!=fa[node]){
                dfs2(u,u);//开辟重链 
            }
        }
    }

    void create_tree(int node,int l,int r){
        lazy[node]=0;
        if(l==r){
            tree[node]=a[rank[l]];
            return ;
        }
        int mid=(l+r)>>1;
        create_tree(lr,l,mid);
        create_tree(rr,mid+1,r);
        tree[node]=tree[lr]+tree[rr];//在本题中毫无意义
    }

    void down(int node,int l,int r){
        if(!lazy[node]) return ;
        int mid=(l+r)>>1;
        tree[lr]+=(mid-l+1)*lazy[node];
        tree[rr]+=(r-mid)*lazy[node];
        lazy[lr]+=lazy[node];
        lazy[rr]+=lazy[node];
        lazy[node]=0;
        return ;
    }

    void update(int node,int l,int r,int be,int en,int ad){
        if(be<=l && en>=r){
            lazy[node]+=ad;
            tree[node]+=(r-l+1)*ad;
            return ;
        }
        down(node,l,r);
        int mid=(l+r)>>1;
        if(be<=mid) update(lr,l,mid,be,en,ad);
        if(mid<en) update(rr,mid+1,r,be,en,ad);
        tree[node]=tree[lr]+tree[rr];
        return ;
    }

    int query(int node,int l,int r,int be,int en){
        if(be<=l && en>=r){
            return tree[node];
        }
        down(node,l,r);
        int mid=(l+r)>>1,md=0;
        if(be<=mid) md+=query(lr,l,mid,be,en);
        if(mid<en) md+=query(rr,mid+1,r,be,en);
        tree[node]=tree[lr]+tree[rr];
        return md;
    }

    void change(int l,int r,int mdzz){
        /*不同重链中*/
        while(top[l]!=top[r]){
            if(dep[top[l]]<dep[top[r]]) swap(l,r);//深的优先
            update(1,1,n,tid[top[l]],tid[l],mdzz);//维护这一个区间
            l=fa[top[l]];//提上去到另一条重链
        }
        /*同一重链中*/
        if(dep[l]>dep[r]) swap(l,r);//保证序列
        update(1,1,n,tid[l],tid[r],mdzz);
        return ;
    }

    void init(){
        ak(tree);
        memset(begin,0,sizeof(begin));
        memset(son,-1,sizeof(son));
        e=0;sum=0;
    }

    void work(){
        init();
        For(i,1,n){
            scanf("%d",&a[i]);
        }
        For(i,1,m){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        dfs1(1,1,0);
        dfs2(1,1);
        create_tree(1,1,n);
        For(i,1,q){
            char s[2];
            scanf("%s",s);
            if(s[0]=='Q'){
                int x;
                scanf("%d",&x);
                printf("%d\n",query(1,1,n,tid[x],tid[x]));
            }else{
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                if(s[0]=='D') z=-z;
                change(x,y,z);
            }
        }
        return ;
    }
}d;

int main(){
    while(~scanf("%d%d%d",&n,&m,&q)) d.work();
    return 0;
}
发布了51 篇原创文章 · 获赞 6 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_35776579/article/details/54428503