zoukankan      html  css  js  c++  java
  • HDU 5044 Tree --树链剖分

    题意:给一棵树,两种操作: ADD1: 给u-v路径上所有点加上值k, ADD2:给u-v路径上所有边加上k,初始值都为0,问最后每个点和每条边的值,输出。

    解法:树链剖分可做,剖出来如果直接用线段树来区间更新的话会TLE,所以要换一种姿势,有一种树链剖分的经典姿势就是看做树状数组一样,每次加值的时候,比如u->v之间加一个值k,那么在u处+k,v+1处-k即可,然后扫一遍,每次把当前位置要做的操作做完,此时总共加的值就是当前处的值,扫一遍的时候维护的是前缀的和,也就是两个ans不清零。

    这题卡时间太紧,不加读入挂会T,不加输出挂的话跑4921ms,也是飘过,加了输入输出挂才稍微好点,4687ms,可能是树链剖分不够优越

    代码:

    #pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #define lll __int64
    using namespace std;
    #define N 100007
    
    int siz[N];  //子树大小
    int son[N];  //重儿子
    int dep[N];  //深度
    int pos[N],apos[N];  //点在线段树中的位置
    int Top[N];  //所在重链的祖先
    int fa[N];   //父节点
    lll eans[N],nans[N];  //答案
    int head[2*N],tot,POS,n,m;
    struct Edge
    {
        int v,next;
    }G[2*N],Qe[10*N],Qn[10*N];
    int heade[10*N],headn[10*N],tote,totn;
    struct node
    {
        int u,v;
    }edge[N];
    
    void init()
    {
        POS = tot = tote = totn = 0;
        memset(head,-1,sizeof(head));
        memset(son,-1,sizeof(son));
        memset(heade,-1,sizeof(heade));
        memset(headn,-1,sizeof(headn));
    }
    
    void addedge(int u,int v)
    {
        G[tot].v = v, G[tot].next = head[u], head[u] = tot++;
        G[tot].v = u, G[tot].next = head[v], head[v] = tot++;
    }
    
    void ADDNedge(int u,int v)  //代替vector来存操作
    {
        Qn[totn].v = v, Qn[totn].next = headn[u], headn[u] = totn++;
    }
    
    void ADDEedge(int u,int v)  //代替vector来存操作
    {
        Qe[tote].v = v, Qe[tote].next = heade[u], heade[u] = tote++;
    }
    
    void dfs(int u,int f)
    {
        dep[u] = dep[f]+1;
        siz[u] = 1;
        for(int i=head[u];i!=-1;i=G[i].next)
        {
            int v = G[i].v;
            if(v == f) continue;
            fa[v] = u;
            dfs(v,u);
            if(son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v;
            siz[u] += siz[v];
        }
    }
    
    void dfs2(int u,int top)
    {
        pos[u] = ++POS;
        apos[POS] = u;
        Top[u] = top;
        if(son[u] != -1) dfs2(son[u],top);
        for(int i=head[u];i!=-1;i=G[i].next)
        {
            int v = G[i].v;
            if(v != fa[u] && v != son[u])
                dfs2(v,v);
        }
    }
    
    void AddEdge(int u,int v,int k)
    {
        int fx = Top[u], fy = Top[v];
        while(fx != fy)
        {
            if(dep[fx] < dep[fy])
            {
                swap(u,v);
                swap(fx,fy);
            }
            ADDEedge(pos[fx],k);
            ADDEedge(pos[u]+1,-k);
            u = fa[fx];
            fx = Top[u];
        }
        if(dep[u] > dep[v]) swap(u,v);
        ADDEedge(pos[son[u]],k);
        ADDEedge(pos[v]+1,-k);
    }
    
    void AddNode(int u,int v,int k)
    {
        int fx = Top[u], fy = Top[v];
        while(fx != fy)
        {
            if(dep[fx] < dep[fy])
            {
                swap(u,v);
                swap(fx,fy);
            }
            ADDNedge(pos[fx],k);
            ADDNedge(pos[u]+1,-k);
            u = fa[fx];
            fx = Top[u];
        }
        if(dep[u] > dep[v]) swap(u,v);
        ADDNedge(pos[u],k);
        ADDNedge(pos[v]+1,-k);
    }
    
    inline int in()
    {
        char ch;
        int a = 0;
        while((ch = getchar()) == ' ' || ch == '
    ');
        a += ch - '0';
        while((ch = getchar()) != ' ' && ch != '
    ')
        {
            a *= 10;
            a += ch - '0';
        }
        return a;
    }
    
    inline void out(lll num){
        bool flag=false;
        if(num<0){
            putchar('-');
            num=-num;
        }
        int ans[22],top=0;
        while(num!=0){
            ans[top++]=num%10;
            num/=10;
        }
        if(top==0)
            putchar('0');
        for(int i=top-1;i>=0;i--){
            char ch=ans[i]+'0';
            putchar(ch);
        }
    }
    
    int main()
    {
        int u,v,k,i,j,t,cs = 1;
        char ss[10];
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            init();
            for(i=1;i<n;i++)
            {
                edge[i].u = in();
                edge[i].v = in();
                addedge(edge[i].u,edge[i].v);
            }
            dep[0] = 0;
            dfs(1,0);
            dfs2(1,1);
            while(m--)
            {
                scanf("%s",ss);
                u = in(), v = in(), k = in();
                if(ss[3] == '1')    //node
                    AddNode(u,v,k);
                else
                    AddEdge(u,v,k);
            }
            printf("Case #%d:
    ",cs++);
            lll ansedge = 0,ansnode = 0;
            for(i=1;i<=n;i++)
            {
                for(j=headn[i];j!=-1;j=Qn[j].next)
                    ansnode += Qn[j].v;
                for(j=heade[i];j!=-1;j=Qe[j].next)
                    ansedge += Qe[j].v;
                nans[apos[i]] = ansnode;
                eans[apos[i]] = ansedge;
            }
            for(i=1;i<=n;i++)
            {
                out(nans[i]);
                printf("%c",i==n?'
    ':' ');
            }
            for(i=1;i<n;i++)
            {
                int u = edge[i].u, v = edge[i].v;
                if(dep[u] > dep[v]) swap(u,v);
                out(eans[v]);
                printf("%c",i==n-1?'
    ':' ');
            }
            if(n == 1) puts("");    //PE..
        }
        return 0;
    }
    View Code
  • 相关阅读:
    python——二分查找算法
    python实现二分查找
    git merge 与 git rebase的区别
    mysql查询表死锁和结束死锁的方法
    mysql的undo log和redo log
    Python中给List添加元素的4种方法
    输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字
    Python中生成器和迭代器的区别(代码在Python3.5下测试):
    mysql锁
    每天一个linux命令(46):vmstat命令
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4003880.html
Copyright © 2011-2022 走看看