• HDU 3966 (树链剖分+线段树)


    Problem Aragorn's Story (HDU 3966)

    题目大意

      给定一颗树,有点权。

      要求支持两种操作,将一条路径上的所有点权值增加或减少ai,询问某点的权值。

    解题分析

      树链剖分模板题。

      实质上树链剖分进行了点对点的一次映射,保证了重链上的点在线段树上的位置是连续的。

      树链剖分的两个性质(转):

        性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v];

        性质2:从根到某一点的路径上轻链、重链的个数都不大于logn。

      保证了一个区间的时间复杂度是log2(n)。

      要分清3种标号含义(易混) :树中节点标号,树中节点对应线段树中位置标号,线段树中区间标号。

      树链剖分相关数组意义 :

        size[i] :以i为根的子树的大小

        fa[i] :i节点的父亲

        dep[i] :i节点的深度

        son[i] :i节点的重儿子(所有儿子中size最大的)

        w[i] :i节点在线段树中对应的位置

        top[i] :i节点所在重链的顶端节点,若为轻链,则为自身。

        rank[i] :线段树中所对应树中节点。

    参考程序

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <cmath>
      5 
      6 #define V 50008
      7 #define E 100008
      8 #define lson l,m,rt<<1
      9 #define rson m+1,r,rt<<1|1
     10 
     11 int n,m,Q;
     12 int a[V],size[V],dep[V],fa[V],top[V],w[V],son[V],rank[V];
     13 int sum[V << 2],lazy[V << 2];
     14 
     15 struct line{
     16     int u,v,nt;
     17 }eg[E];
     18 int lt[V],summ,cnt;
     19 
     20 void adt(int u,int v){
     21     eg[++summ].u=u; eg[summ].v=v; eg[summ].nt=lt[u]; lt[u]=summ;
     22 }
     23 
     24 void add(int u,int v){
     25     adt(u,v); adt(v,u);
     26 }
     27 
     28 void dfs1(int u){
     29     size[u]=1; son[u]=0;
     30     for (int i=lt[u];i;i=eg[i].nt){
     31         int v=eg[i].v;
     32         if (v!=fa[u]){
     33             fa[v]=u;
     34             dep[v]=dep[u]+1;
     35             dfs1(v);
     36             size[u]+=size[v];
     37             if (size[v]>size[son[u]]) son[u]=v;
     38         }
     39     }
     40 }
     41 
     42 void dfs2(int u,int tp,int x){
     43     top[u]=tp; w[u]=++cnt; rank[cnt]=u;
     44     if (son[u]) dfs2(son[u],tp,1);
     45     for (int i=lt[u];i;i=eg[i].nt){
     46         int v=eg[i].v;
     47         if (v==son[u] || v==fa[u]) continue;
     48         dfs2(v,v,2);
     49     }
     50 }
     51 
     52 void init(){
     53     memset(lt,0,sizeof(lt));
     54     summ=1; cnt=0;
     55     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
     56     for (int i=1;i<=m;i++){
     57         int u,v;
     58         scanf("%d %d",&u,&v);
     59         add(u,v);
     60     }
     61     dep[1]=1; fa[1]=0; 
     62     dfs1(1);
     63     dfs2(1,1,1);
     64 }
     65 
     66 void pushup(int rt){
     67     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
     68 }
     69 
     70 void pushdown(int rt,int m){
     71     if (lazy[rt]){
     72         lazy[rt<<1]+=lazy[rt];
     73         lazy[rt<<1|1]+=lazy[rt];
     74         sum[rt<<1]+=lazy[rt]*(m-m / 2);
     75         sum[rt<<1|1]+=lazy[rt]*(m / 2);
     76         lazy[rt]=0;
     77     }
     78 }
     79 
     80 void build(int l,int r,int rt){
     81     lazy[rt]=0;
     82     if (l==r){
     83         sum[rt]=a[rank[l]];
     84         return;
     85     }
     86     int m=(l+r)/2;
     87     build(lson);
     88     build(rson);
     89     pushup(rt);
     90 }
     91 
     92 void update(int L,int R,int val,int l,int r,int rt){
     93     if (L<=l && r<=R){
     94         sum[rt]+=val*(r-l+1);
     95         lazy[rt]+=val;
     96         return;
     97     }
     98     pushdown(rt,r-l+1);
     99     int m=(l+r)>>1;
    100     if (L<=m) update(L,R,val,lson);
    101     if (m< R) update(L,R,val,rson);
    102     pushup(rt);
    103 }
    104 
    105 int query(int x,int l,int r,int rt){
    106     if (l==r){
    107         return sum[rt];
    108     }
    109     pushdown(rt,r-l+1);
    110     int m=(l+r)>>1;
    111     if (x<=m) return query(x,lson);
    112     if (m< x) return query(x,rson);
    113 }
    114 
    115 void change(int x,int y,int val){
    116     while (top[x]!=top[y]){
    117         if (dep[top[x]]<dep[top[y]]) std::swap(x,y);
    118         update(w[top[x]],w[x],val,1,n,1);
    119         x=fa[top[x]];
    120     }
    121     if (dep[x]>dep[y]) std::swap(x,y);
    122     update(w[x],w[y],val,1,n,1);
    123 }
    124 
    125 int main(){
    126     while (~scanf("%d %d %d",&n,&m,&Q)){
    127         init();
    128         build(1,n,1);
    129         while (Q--){
    130             char s[2];
    131             int x,y,z;
    132             scanf("%s",s);
    133             if (s[0]=='I'){
    134                 scanf("%d %d %d",&x,&y,&z);
    135                 change(x,y,z);
    136             }    
    137             if (s[0]=='D'){
    138                 scanf("%d %d %d",&x,&y,&z);
    139                 change(x,y,-z);
    140             }
    141             if (s[0]=='Q'){
    142                 scanf("%d",&x);
    143                 printf("%d
    ",query(w[x],1,n,1));
    144             }
    145         }
    146     }
    147 }
    View Code
  • 相关阅读:
    WORD窗体保护密码清除
    在Fedora 23 Server和Workstation上安装LAMP(Linux, Apache, MariaDB和PHP)
    firefox 提示 ssl_error_unsupported_version 的解决方法
    算法题:求一个序列S中所有包含T的子序列(distinct sub sequence)
    Django模板输出Dict所有Value的效率问题
    笔记:LNK2001不代表链接器真的需要链接相关符号
    Windows Restart Manager 重启管理器
    advapi32.dll kernel32.dll 中的两套注册表API
    使用GDI+保存带Alpha通道的图像(续)
    使用GDI+保存带Alpha通道的图像
  • 原文地址:https://www.cnblogs.com/rpSebastian/p/5722270.html
Copyright © 2020-2023  润新知