• HDU 3966 Aragorn's Story 树链剖分


        第一道树链剖分,学习的时候参考了下面连接博主的文章,含义深入浅出,看了之后就非常清楚树链剖分的原理了:http://blog.sina.com.cn/s/blog_7a1746820100wp67.html

        个人的理解是,树链剖分实际上是在树于链的结构中找到了一种平衡,一个单纯的链在树链剖分的角度来看是一条长长的重链,在处理的时候等效于平常的区间线段树,但是当变成树路径的时候,边不具有连续性,因此很难去用线段树去维护,所以自然的,有人想出了一个办法,通过某种办法对树上的链进行编号,使得两个点的路径上的边尽可能多的连续起来,而且连续的和不连续的边加起来不超过logn条,这样我在更新线段树的时候只需要找出logn条这些边,每次logn的更新,所以每次修改树路径就是log^2n的代价.

        用术语来说,重链就是连续的边,轻边就是不连续的.所以树链剖分实际上是利用logn的代价将树路径转换成了区间.所以对树路径的所有操作都转化成最基本的线段树的问题.你所要做的就是做两次dfs,分好轻重链,两边不断往上更新到lca处.链接中的博客给了一个很好的范本.

        题目给的是边权,点权也是同样可以处理的,将点权放在连向父亲的那条边上(对于非根结点).对于根结点,我们可以再弄一个根的根结点(下面代码里就是0号)连一条边,最后每个点权都会对应于一条边.其中相应的代码中有些细节也是需要修改的.不过自己写的跑的微慢呀...用了2s..

    #pragma comment(linker, "/STACK:102400000,102400000")
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<vector>
    #include<cmath>
    #define maxn 50000
    #define ll long long
    using namespace std;
    
    vector<int> G[maxn+50];
    int n,m,p;
    int son[maxn+50],w[maxn+50],fa[maxn+50],siz[maxn+50],top[maxn+50],dep[maxn+50],totw;
    int edge[maxn+50];
    int wht[maxn+50];
    
    struct Node
    {
        int l,r;
        ll sum,add;
    }N[4*maxn+50];
    
    void pushUp(int i)
    {
        N[i].sum=N[i<<1].sum+N[i<<1|1].sum;
    }
    void pushDown(int i)
    {
        if(N[i].add!=0){
            if(N[i].l!=N[i].r){
                int t=N[i].add;
                N[i<<1].sum+=(N[i<<1].r-N[i<<1].l+1)*t;
                N[i<<1|1].sum+=(N[i<<1|1].r-N[i<<1|1].l+1)*t;
                N[i<<1].add+=t;
                N[i<<1|1].add+=t;
            }
            N[i].add=0;
        }
    }
    
    void build(int i,int L,int R)
    {
        N[i].l=L;N[i].r=R;N[i].add=0;
        if(L==R){
            N[i].sum=edge[L];
            return;
        }
        int M=(L+R)>>1;
        build(i<<1,L,M);
        build(i<<1|1,M+1,R);
        pushUp(i);
    }
    
    void add(int i,int L,int R,int val)
    {
        if(N[i].l==L&&N[i].r==R){
            N[i].sum+=(R-L+1)*val;
            N[i].add+=val;
            return;
        }
        pushDown(i);
        int M=(N[i].l+N[i].r)>>1;
        if(M>=R){
            add(i<<1,L,R,val);
        }
        else if(M<L){
            add(i<<1|1,L,R,val);
        }
        else{
            add(i<<1,L,M,val);
            add(i<<1|1,M+1,R,val);
        }
        pushUp(i);
    }
    
    int query(int i,int L,int R)
    {
        if(N[i].l==L&&N[i].r==R){
            return N[i].sum;
        }
        pushDown(i);
        int M=(N[i].l+N[i].r)>>1;
        if(M>=R){
            return query(i<<1,L,R);
        }
        else if(M<=L){
            return query(i<<1|1,L,R);
        }
        else{
            return query(i<<1,L,M)+query(i<<1|1,M+1,R);
        }
        pushUp(i);
    }
    
    void dfs1(int v)
    {
        siz[v]=1;son[v]=0;int msize=0;
        for(int i=0;i<G[v].size();++i){
            int u=G[v][i];
            if(u==fa[v]) continue;
            fa[u]=v;
            dep[u]=dep[v]+1;
            dfs1(u);
            if(siz[u]>msize) {son[v]=u;msize=siz[u];}
            siz[v]+=siz[u];
        }
    }
    
    void dfs2(int v,int tp)
    {
        w[v]=++totw;top[v]=tp;edge[w[v]]=wht[v];
        if(son[v]!=0) dfs2(son[v],top[v]);
        for(int i=0;i<G[v].size();++i){
            int u=G[v][i];
            if(u!=fa[v]&&u!=son[v]){
                dfs2(u,u);
            }
        }
    }
    
    void initEdge()
    {
        fa[0]=totw=dep[0]=0;
        dfs1(0);dfs2(0,0);
        build(1,1,n+1);
    }
    
    ll query_path(int va,int vb)
    {
        ll res=0;
        int f1=top[va],f2=top[vb];
        while(f1!=f2)
        {
            if(dep[f1]<dep[f2]){
                swap(f1,f2);swap(va,vb);
            }
            res+=(ll)query(1,w[f1],w[va]);
            va=fa[f1];f1=top[va];
        }
        if(va==vb) return res+query(1,w[va],w[vb]);
        if(dep[va]>dep[vb]) swap(va,vb);
        res+=(ll)query(1,w[va],w[vb]);
        return res;
    }
    
    void add_path(int va,int vb,int val)
    {
        int f1=top[va],f2=top[vb];
        while(f1!=f2)
        {
            if(dep[f1]<dep[f2]){
                swap(f1,f2);swap(va,vb);
            }
            add(1,w[f1],w[va],val);
            va=fa[f1];f1=top[va];
        }
        if(va==vb) {add(1,w[va],w[va],val);return;}
        if(dep[va]>dep[vb]) swap(va,vb);
        add(1,w[va],w[vb],val);
    }
    
    int main()
    {
        while(cin>>n>>m>>p)
        {
            for(int i=1;i<=n;++i){
                scanf("%d",&wht[i]);
                G[i].clear();
            }
            int u,v;
            for(int i=0;i<n-1;++i){
                scanf("%d%d",&u,&v);
                G[u].push_back(v);G[v].push_back(u);
            }
            G[0].push_back(1);
            initEdge();
            char s[3];int val;
            for(int i=0;i<p;++i){
                scanf("%s",&s);
                if(s[0]=='I'||s[0]=='D'){
                    scanf("%d%d%d",&u,&v,&val);
                    if(s[0]=='I'){
                        add_path(u,v,val);
                    }
                    else{
                        add_path(u,v,-val);
                    }
                }
                else{
                    scanf("%d",&u);
                    printf("%d
    ",query_path(u,u));
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    lamp
    Mysql主从
    Mysql多实例部署
    Xtrabackup备份与恢复
    Mysql备份工具mysqldump
    Mysql进阶
    Mysql基础
    MySql进阶管理备份操作和Xtrabackup使用
    MySql的基础配置和操作
    java学习——基础入门(2)
  • 原文地址:https://www.cnblogs.com/chanme/p/3415673.html
Copyright © 2020-2023  润新知