zoukankan      html  css  js  c++  java
  • HDU 3966 Aragorn's Story --树链剖分

    题意: 树上路径之间的点统一加减k,查询某点的值

    解法:不会LCA的解法,于是用树链剖分了,比较简单的剖分,然后用线段树维护就行了,相当于区间更新,单点查询,查询点 i 的值时,只需在线段树中查询pos[u]位置的值即可。

    加IO优化900+ms

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 50007
    
    int siz[N];  //子树大小
    int son[N];  //重儿子
    int dep[N];  //深度
    int pos[N];  //在线段树中的位置
    int Top[N];  //所在重链的祖先
    int fa[N];   //父节点
    int head[2*N],tot,POS,n,m,q;
    struct Edge
    {
        int v,next;
    }G[2*N];
    int tree[4*N],mark[4*N],a[N];
    
    void init()
    {
        POS = tot = 0;
        memset(head,-1,sizeof(head));
        memset(son,-1,sizeof(son));
        memset(tree,0,sizeof(tree));
        memset(mark,0,sizeof(mark));
    }
    
    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 pushdown(int l,int r,int rt)
    {
        int mid = (l+r)/2;
        if(mark[rt])
        {
            mark[2*rt] += mark[rt];
            mark[2*rt+1] += mark[rt];
            tree[2*rt] += mark[rt]*(mid-l+1);
            tree[2*rt+1] += mark[rt]*(r-mid);
            mark[rt] = 0;
        }
    }
    
    void update(int l,int r,int aa,int bb,int k,int rt)
    {
        if(aa <= l && bb >= r)
        {
            tree[rt] += k*(r-l+1);
            mark[rt] += k;
            return;
        }
        int mid = (l+r)/2;
        if(aa <= mid)
            update(l,mid,aa,bb,k,2*rt);
        if(bb > mid)
            update(mid+1,r,aa,bb,k,2*rt+1);
    }
    
    int query(int l,int r,int pos,int rt)
    {
        if(l == r)
            return tree[rt];
        pushdown(l,r,rt);
        int mid = (l+r)/2;
        if(pos <= mid) return query(l,mid,pos,2*rt);
        else return query(mid+1,r,pos,2*rt+1);
    }
    
    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 father)
    {
        pos[u] = ++POS;
        Top[u] = father;
        if(son[u] != -1) dfs2(son[u],father);
        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 Change(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);
            }
            update(1,POS,pos[fx],pos[u],k,1);
            u = fa[fx];
            fx = Top[u];
        }
        if(dep[u] > dep[v]) swap(u,v);
        update(1,POS,pos[u],pos[v],k,1);
    }
    
    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;
    }
    
    int main()
    {
        int u,v,k,i;
        char ss[5];
        while(scanf("%d%d%d",&n,&m,&q)!=EOF)
        {
            init();
            for(i=1;i<=n;i++)
                a[i] = in();
            for(i=1;i<n;i++)
            {
                u = in(), v = in();
                addedge(u,v);
            }
            dep[0] = 0;
            dfs(1,0);
            dfs2(1,1);
            for(i=1;i<=n;i++)
                update(1,POS,pos[i],pos[i],a[i],1);
            while(q--)
            {
                scanf("%s",ss);
                if(ss[0] == 'Q')
                {
                    u = in();
                    printf("%d
    ",query(1,POS,pos[u],1));
                }
                else
                {
                    u = in(), v = in(), k = in();
                    if(ss[0] == 'I')
                        Change(u,v,k);
                    else
                        Change(u,v,-k);
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    PHP数组(数组正则表达式、数组、预定义数组)
    面向对象。OOP三大特征:封装,继承,多态。 这个讲的是【封存】
    uvalive 3938 "Ray, Pass me the dishes!" 线段树 区间合并
    LA4329 Ping pong 树状数组
    HDU 1257 最少拦截系统
    HDU 1260 Tickets
    codeforce 621D
    codeforce 621C Wet Shark and Flowers
    codeforce 621B Wet Shark and Bishops
    codeforce 621A Wet Shark and Odd and Even
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4009374.html
Copyright © 2011-2022 走看看