zoukankan      html  css  js  c++  java
  • hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966

     https://www.cnblogs.com/violet-acmer/p/9711441.html

    学习资料:

      [1]线段树区间更新:https://blog.csdn.net/zhhe0101/article/details/53871453

               https://yq.aliyun.com/articles/252586

      [2]树链剖分:http://blog.sina.com.cn/s/blog_7a1746820100wp67.html

             https://wenku.baidu.com/view/7548d8706ad97f192279168884868762caaebbfc.html?from=search

    题意:

      敌军有N个营地,这N个营地通过M条边连接;
      每个营地有且仅有一条边连接(意味着M=N-1,就是一颗含有N个节点的树)
      要求支持两种操作:
      1营地u与营地v以及其之间的所有营地增加或减少ai个士兵。
      2询问营地u当前含有的士兵个数

    题解:

      树链剖分模板题。

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

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

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

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

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

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

    树链剖分相关数组意义 :

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

      fa[i] : i节点的父亲

      depth[i]  : i节点的深度

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

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

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

      rid[i] : 线段树中所对应树中节点(作用和tid[ ] 正好相反)。

    AC代码:

      摘抄自大佬博客:

      分析:典型的树链剖分题目,先进行剖分,然后用线段树去维护即可,注意HDU的OJ采用Windows系统,容易爆栈,所以在代码前面加上:

      #pragma comment(linker, "/STACK:1024000000,1024000000")进行手动扩栈。

      (但不加也可以AC)

      1 //#pragma comment(linker, "/STACK:1024000000,1024000000")
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<cstring>
      5 using namespace std;
      6 #define ls(x)((x)<<1)
      7 #define rs(x)((x)<<1 | 1)
      8 const int maxn=5e4+10;
      9 
     10 int A[maxn];
     11 //========链式前向星========
     12 struct Node1
     13 {
     14     int to;
     15     int next;
     16 }edge[maxn<<1];
     17 int head[maxn];
     18 int cnt;
     19 void addEdge(int u,int v)
     20 {
     21     edge[cnt].to=v;
     22     edge[cnt].next=head[u];
     23     head[u]=cnt++;
     24 }
     25 //==========================
     26 //=========树链剖分=========
     27 int fa[maxn];
     28 int son[maxn];
     29 int tid[maxn];
     30 int rid[maxn];
     31 int siz[maxn];
     32 int top[maxn];
     33 int depth[maxn];
     34 int label;
     35 
     36 void dfs1(int u,int f,int d)
     37 {
     38     fa[u]=f;
     39     siz[u]=1;
     40     depth[u]=d;
     41     for(int i=head[u];~i;i=edge[i].next)
     42     {
     43         int to=edge[i].to;
     44         if(to != f)
     45         {
     46             dfs1(to,u,d+1);
     47             siz[u] += siz[to];
     48             if(son[u] == -1 || siz[to] > siz[son[u]])
     49                 son[u]=to;
     50         }
     51     }
     52 }
     53 void dfs2(int u,int newTop)
     54 {
     55     top[u]=newTop;
     56     tid[u]=++label;
     57     rid[tid[u]]=u;
     58     if(son[u] == -1)
     59         return ;
     60     dfs2(son[u],newTop);
     61     for(int i=head[u];~i;i=edge[i].next)
     62     {
     63         int to=edge[i].to;
     64         if(to != son[u] && to != fa[u])
     65             dfs2(to,to);
     66     }
     67 }
     68 //==========================
     69 //==========线段树==========
     70 struct Node2
     71 {
     72     int l,r;
     73     int val;
     74     int lazy;
     75     int mid(){
     76         return l+((r-l)>>1);
     77     }
     78 }segTree[maxn<<2];
     79 void buildTree(int l,int r,int pos)
     80 {
     81     segTree[pos].l=l,segTree[pos].r=r;
     82     segTree[pos].lazy=0;
     83     if(l == r)
     84     {
     85         segTree[pos].val=A[rid[l]];
     86         return ;
     87     }
     88     int mid=l+((r-l)>>1);
     89     buildTree(l,mid,ls(pos));
     90     buildTree(mid+1,r,rs(pos));
     91 }
     92 void pushDown(int pos)
     93 {
     94 
     95     if(segTree[pos].lazy != 0)
     96     {
     97         segTree[ls(pos)].lazy += segTree[pos].lazy;
     98         segTree[rs(pos)].lazy += segTree[pos].lazy;
     99 
    100         //segTree[ls(pos)].val += segTree[pos].lazy;
    101         //segTree[rs(pos)].val += segTree[pos].lazy;
    102 
    103         segTree[pos].lazy=0;
    104     }
    105 }
    106 void update(int a,int b,int val,int pos)
    107 {
    108     if(a <= segTree[pos].l && b >= segTree[pos].r)
    109     {
    110         segTree[pos].lazy += val;
    111         //segTree[pos].val += val;
    112         return ;
    113     }
    114     pushDown(pos);
    115 
    116     int mid=segTree[pos].mid();
    117     if(b <= mid)
    118         update(a,b,val,ls(pos));
    119     else if(a > mid)
    120         update(a,b,val,rs(pos));
    121     else
    122     {
    123         update(a,mid,val,ls(pos));
    124         update(mid+1,b,val,rs(pos));
    125     }
    126 }
    127 int query(int k,int pos)
    128 {
    129     if(segTree[pos].l == segTree[pos].r)
    130         return segTree[pos].val+segTree[pos].lazy;
    131 
    132     pushDown(pos);
    133     int mid=segTree[pos].mid();
    134 
    135     if(k <= mid)
    136         return query(k,ls(pos));
    137     else
    138         return query(k,rs(pos));
    139 }
    140 //==========================
    141 void Find(int a,int b,int val)
    142 {
    143     while(top[a] != top[b])
    144     {
    145         if(depth[top[a]] > depth[top[b]])
    146         {
    147             update(tid[top[a]],tid[a],val,1);
    148             a=fa[top[a]];
    149         }
    150         else
    151         {
    152             update(tid[top[b]],tid[b],val,1);
    153             b=fa[top[b]];
    154         }
    155     }
    156     if(tid[a] > tid[b])
    157         swap(a,b);
    158     update(tid[a],tid[b],val,1);
    159 }
    160 
    161 void init()
    162 {
    163     cnt=0;
    164     memset(head,-1,sizeof(head));
    165     label=0;
    166     memset(son,-1,sizeof(son));
    167 }
    168 int main()
    169 {
    170     int n,m,q;
    171     while(~scanf("%d%d%d",&n,&m,&q))
    172     {
    173         init();
    174         for(int i=1;i <= n;++i)
    175             scanf("%d",A+i);
    176         for(int i=1;i <= m;++i)
    177         {
    178             int u,v;
    179             scanf("%d%d",&u,&v);
    180             addEdge(u,v);
    181             addEdge(v,u);
    182         }
    183         dfs1(1,1,0);
    184         dfs2(1,1);
    185         buildTree(1,label,1);
    186         char op[3];
    187         for(int i=1;i <= q;++i)
    188         {
    189             scanf("%s",op);
    190             if(op[0] == 'Q')
    191             {
    192                 int c;
    193                 scanf("%d",&c);
    194                 printf("%d
    ",query(tid[c],1));
    195             }
    196             else
    197             {
    198                 int c1,c2,k;
    199                 scanf("%d%d%d",&c1,&c2,&k);
    200                 if(op[0] == 'D')
    201                     k = -k;
    202                 Find(c1,c2,k);
    203             }
    204         }
    205     }
    206     return 0;
    207 }
    View Code

    分割线:2019.5.10

    省赛倒计时2天;

    重新温习了一下树链剖分,改了改代码风格:

      1 #pragma comment(linker,"/STACK:1024000000,1024000000")///手动扩栈
      2 #include<bits/stdc++.h>
      3 using namespace std;
      4 #define ls(x) (x<<1)
      5 #define rs(x) (x<<1|1)
      6 #define mem(a,b) memset(a,b,sizeof(a))
      7 const int maxn=5e4+50;
      8 
      9 int n,m,q;///n个点 ,m条边(m=n-1),q次询问
     10 int a[maxn];///a[i]:初始i营地有a[i]个士兵
     11 int num;
     12 int head[maxn];
     13 struct Edge
     14 {
     15     int to;
     16     int next;
     17 }G[maxn<<1];
     18 void addEdge(int u,int v)
     19 {
     20     G[num]=Edge{v,head[u]};
     21     head[u]=num++;
     22 }
     23 int fa[maxn];
     24 int tid[maxn];
     25 int rid[maxn];
     26 int siz[maxn];
     27 int son[maxn];
     28 int top[maxn];
     29 int dep[maxn];
     30 struct Seg
     31 {
     32     int l,r;
     33     int val;
     34     int lazy;
     35     int mid(){return l+((r-l)>>1);}
     36     int len(){return r-l+1;};
     37 }seg[maxn<<2];
     38 
     39 void pushDown(int pos)
     40 {
     41     int &lazy=seg[pos].lazy;
     42     if(lazy)
     43     {
     44         seg[ls(pos)].lazy += lazy;
     45         seg[rs(pos)].lazy += lazy;
     46     }
     47     lazy=0;
     48 }
     49 void buildSegTree(int l,int r,int pos)
     50 {
     51     seg[pos].l=l;
     52     seg[pos].r=r;
     53     seg[pos].lazy=0;
     54     seg[pos].val=0;
     55     if(l == r)
     56     {
     57         seg[pos].val=a[rid[l]];///l点在树中对应的编号rid[l]
     58         return ;
     59     }
     60     int mid=l+((r-l)>>1);
     61     buildSegTree(l,mid,ls(pos));
     62     buildSegTree(mid+1,r,rs(pos));
     63 }
     64 int Query(int l,int pos)
     65 {
     66     if(seg[pos].l == seg[pos].r)
     67         return seg[pos].val+seg[pos].lazy;
     68 
     69     pushDown(pos);
     70 
     71     int mid=seg[pos].mid();
     72     if(l <= mid)
     73         return Query(l,ls(pos));
     74     else
     75         return Query(l,rs(pos));
     76 }
     77 void Update(int l,int r,int pos,int val)
     78 {
     79     if(seg[pos].l == l && seg[pos].r == r)
     80     {
     81         seg[pos].lazy += val;
     82         return ;
     83     }
     84     pushDown(pos);
     85 
     86     int mid=seg[pos].mid();
     87     if(r <= mid)
     88         Update(l,r,ls(pos),val);
     89     else if(l > mid)
     90         Update(l,r,rs(pos),val);
     91     else
     92     {
     93         Update(l,mid,ls(pos),val);
     94         Update(mid+1,r,rs(pos),val);
     95     }
     96 }
     97 void Find(int u,int v,int val)
     98 {
     99     while(top[u] != top[v])///u,v不在同一条重链上
    100     {
    101         if(dep[top[u]] > dep[top[v]])
    102             swap(u,v);
    103 
    104         Update(tid[top[v]],tid[v],1,val);///让u,v一步一步靠到同一条重链上
    105         v=fa[top[v]];
    106     }
    107     ///return 语句根据题意而定
    108     ///再此题中,u==v时就是单点更新
    109 //    if(u == v)
    110 //        return ;
    111     if(dep[u] > dep[v])
    112         swap(u,v);
    113     ///这次不是tid[son[u]],因为上次是边权存在了儿子节点里
    114     Update(tid[u],tid[v],1,val);
    115 }
    116 void DFS1(int u,int f,int depth)
    117 {
    118     fa[u]=f;
    119     siz[u]=1;
    120     dep[u]=depth;
    121     for(int i=head[u];~i;i=G[i].next)
    122     {
    123         int v=G[i].to;
    124         if(v == f)
    125             continue;
    126 
    127         DFS1(v,u,depth+1);
    128 
    129         siz[u] += siz[v];
    130         if(son[u] == -1 || siz[v] > siz[son[u]])
    131             son[u]=v;
    132     }
    133 }
    134 void DFS2(int u,int anc,int &k)
    135 {
    136     tid[u]=++k;
    137     rid[k]=u;
    138     top[u]=anc;
    139     if(son[u] == -1)
    140         return ;
    141     DFS2(son[u],anc,k);
    142 
    143     for(int i=head[u];~i;i=G[i].next)
    144     {
    145         int v=G[i].to;
    146         if(v != fa[u] && v != son[u])
    147             DFS2(v,v,k);
    148     }
    149 }
    150 void Solve()
    151 {
    152     DFS1(1,0,0);
    153     int k=0;
    154     DFS2(1,1,k);
    155     buildSegTree(1,k,1);
    156 
    157     char order[10];
    158     while(q--)
    159     {
    160         scanf("%s",order);
    161         if(order[0] == 'Q')
    162         {
    163             int u;
    164             scanf("%d",&u);
    165             printf("%d
    ",Query(tid[u],1));///单点查询,查询u营地当前的人数
    166         }
    167         else
    168         {
    169             int u,v,val;
    170             scanf("%d%d%d",&u,&v,&val);///区间更新,更新营地[u,v]人数 +val
    171             if(order[0] == 'D')
    172                 val=-val;///人数减少
    173             Find(u,v,val);
    174         }
    175     }
    176 }
    177 void Init()
    178 {
    179     num=0;
    180     mem(head,-1);
    181     mem(son,-1);
    182 }
    183 int main()
    184 {
    185     while(~scanf("%d%d%d",&n,&m,&q))
    186     {
    187         Init();
    188         for(int i=1;i <= n;++i)
    189             scanf("%d",a+i);
    190         for(int i=1;i <= m;++i)
    191         {
    192             int u,v;
    193             scanf("%d%d",&u,&v);
    194             addEdge(u,v);
    195             addEdge(v,u);
    196         }
    197         Solve();
    198     }
    199     return 0;
    200 }
    View Code
  • 相关阅读:
    webpack优化
    原生js实现平滑滚动
    【大前端攻城狮之路】JavaScript函数式编程
    【大前端攻城狮之路】面试集锦
    【大前端攻城狮之路·二】Javascript&QA⼯程师
    【vue系列之三】从一个vue-pdf-shower,说说vue组件和npm包
    display:box和display:flex填坑之路
    【vue系列之一】使用vue-cli脚手架工具搭建vue-webpack项目
    快速上手微信小程序-快递100
    js面向对象小结(工厂模式,构造函数,原型方法,继承)
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/9723863.html
Copyright © 2011-2022 走看看