zoukankan      html  css  js  c++  java
  • [HAOI2015]树上操作

    题目大意:
      给你一棵n个点的树,以1为根,每个点都有一个点权,要求进行如下操作:
      1.将x这个点的点权加上a;
      2.将以x这个点为根的子树中每个点的点权加上a;
      3.查询从x到根的路径的点权和。

    思路:
      树链剖分。
      对于第2种操作,我们不难发现一个子树中结点在线段树中的编号一定是连续的。
      于是修改子树的操作就是线段树上修改id[x]~id[x]+size[x]-1的操作。

      1 #include<cstdio>
      2 #include<cctype>
      3 #include<vector>
      4 typedef long long int64;
      5 inline int getint() {
      6     register char ch;
      7     register bool neg=false;
      8     while(!isdigit(ch=getchar())) if(ch=='-') neg=true;
      9     register int x=ch^'0';
     10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
     11     return neg?-x:x;
     12 }
     13 const int N=100001;
     14 std::vector<int> e[N];
     15 inline void add_edge(const int &u,const int &v) {
     16     e[u].push_back(v);
     17     e[v].push_back(u);
     18 }
     19 int n,size[N],par[N],dep[N],id[N],son[N],top[N],w[N],node[N];
     20 void dfs1(const int &x,const int &par) {
     21     ::par[x]=par;
     22     dep[x]=dep[par]+1;
     23     size[x]=1;
     24     for(unsigned i=0;i<e[x].size();i++) {
     25         const int &y=e[x][i];
     26         if(y==par) continue;
     27         dfs1(y,x);
     28         size[x]+=size[y];
     29         if(size[y]>size[son[x]]) son[x]=y;
     30     }
     31 }
     32 void dfs2(const int &x) {
     33     id[x]=++id[0];
     34     node[id[x]]=x;
     35     if(x==son[par[x]]) {
     36         top[x]=top[par[x]];
     37     } else {
     38         top[x]=x;
     39     }
     40     if(son[x]) dfs2(son[x]);
     41     for(unsigned i=0;i<e[x].size();i++) {
     42         const int &y=e[x][i];
     43         if(y==par[x]||y==son[x]) continue;
     44         dfs2(y);
     45     }
     46 }
     47 class SegmentTree {
     48     #define _left <<1
     49     #define _right <<1|1
     50     private:
     51         int64 val[N<<2],tag[N<<2];
     52         void push_up(const int &p) {
     53             val[p]=val[p _left]+val[p _right];
     54         }
     55         int size(const int &b,const int &e) const {
     56             return e-b+1;
     57         }
     58         void push_down(const int &p,const int &b,const int &e) {
     59             const int mid=(b+e)>>1;
     60             val[p _left]+=tag[p]*size(b,mid);
     61             val[p _right]+=tag[p]*size(mid+1,e);
     62             tag[p _left]+=tag[p];
     63             tag[p _right]+=tag[p];
     64             tag[p]=0;
     65         }
     66     public:
     67         void build(const int &p,const int &b,const int &e) {
     68             if(b==e) {
     69                 val[p]=w[node[b]];
     70                 return;
     71             }
     72             const int mid=(b+e)>>1;
     73             build(p _left,b,mid);
     74             build(p _right,mid+1,e);
     75             push_up(p);
     76         }
     77         void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x) {
     78             if(b==l&&e==r) {
     79                 val[p]+=(int64)x*size(b,e);
     80                 tag[p]+=x;
     81                 return;
     82             }
     83             const int mid=(b+e)>>1;
     84             push_down(p,b,e);
     85             if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),x);
     86             if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,x);
     87             push_up(p);
     88         }
     89         int64 query(const int &p,const int &b,const int &e,const int &l,const int &r) {
     90             if(b==l&&e==r) {
     91                 return val[p];
     92             }
     93             const int mid=(b+e)>>1;
     94             push_down(p,b,e);
     95             int64 ret=0;
     96             if(l<=mid) ret+=query(p _left,b,mid,l,std::min(mid,r));
     97             if(r>mid) ret+=query(p _right,mid+1,e,std::max(mid+1,l),r);
     98             return ret;
     99         }
    100     #undef _left
    101     #undef _right
    102 };
    103 SegmentTree t;
    104 inline int64 query(int x) {
    105     int64 ret=0;
    106     while(x) {
    107         ret+=t.query(1,1,n,id[top[x]],id[x]);
    108         x=par[top[x]];
    109     }
    110     return ret;
    111 }
    112 int main() {
    113     n=getint();
    114     const int m=getint();
    115     for(register int i=1;i<=n;i++) {
    116         w[i]=getint();
    117     }
    118     for(register int i=1;i<n;i++) {
    119         add_edge(getint(),getint());
    120     }
    121     dfs1(1,0);
    122     dfs2(1);
    123     t.build(1,1,n);
    124     for(register int i=0;i<m;i++) {
    125         const int op=getint(),x=getint();
    126         if(op==1) {
    127             t.modify(1,1,n,id[x],id[x],getint());
    128         }
    129         if(op==2) {
    130             t.modify(1,1,n,id[x],id[x]+size[x]-1,getint());
    131         }
    132         if(op==3) {
    133             printf("%lld
    ",query(x));
    134         }
    135     }
    136     return 0;
    137 }
    View Code

      题目求的是点到根路径上的权值和,那么修改单点对整棵子树所有结点的询问都有贡献。
      给整棵子树增加权值显然也会对整棵子树的询问产生贡献。
      若v是u的子树中的一个点,对结点u为根的子树的每一个结点权值增加a,相当于给针对v的询问答案增加了(dis(u,v)+1)a。
      考虑将树“压扁”,求出树的DFS序。 对于结点u的子树,DFS序范围是dfn[u]~dfn[u]+size[u]-1。
      用线段树维护两个值x和y,分别代表需要乘dis的权值和不需要乘dis的权值,询问时返回dep[u]*x[u]+y[u]即可。

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<vector>
     4 typedef long long int64;
     5 inline int getint() {
     6     register char ch;
     7     register bool neg=false;
     8     while(!isdigit(ch=getchar())) if(ch=='-') neg=true;
     9     register int x=ch^'0';
    10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    11     return neg?-x:x;
    12 }
    13 const int N=100001;
    14 int w[N],dfn[N],size[N],dep[N];
    15 std::vector<int> e[N];
    16 inline void add_edge(const int &u,const int &v) {
    17     e[u].push_back(v);
    18     e[v].push_back(u);
    19 }
    20 void dfs(const int &x,const int &par) {
    21     size[x]=1;
    22     dfn[x]=++dfn[0];
    23     dep[x]=dep[par]+1;
    24     for(unsigned i=0;i<e[x].size();i++) {
    25         const int &y=e[x][i];
    26         if(y==par) continue;
    27         dfs(y,x);
    28         size[x]+=size[y];
    29     }
    30 }
    31 class SegmentTree {
    32     #define _left <<1
    33     #define _right <<1|1
    34     private:
    35         int64 val1[N<<2],val2[N<<2];
    36     public:
    37         void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x,const int64 &y) {
    38             if(b==l&&e==r) {
    39                 val1[p]+=x;
    40                 val2[p]+=y;
    41                 return;
    42             }
    43             const int mid=(b+e)>>1;
    44             if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),x,y);
    45             if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,x,y);
    46         }
    47         int64 query(const int &p,const int &b,const int &e,const int &x) {
    48             int64 ret=val1[p]*dep[x]+val2[p];
    49             if(b==e) return ret;
    50             const int mid=(b+e)>>1;
    51             if(dfn[x]<=mid) ret+=query(p _left,b,mid,x);
    52             if(dfn[x]>mid) ret+=query(p _right,mid+1,e,x);
    53             return ret;
    54         }
    55     #undef _left
    56     #undef _right
    57 };
    58 SegmentTree t;
    59 int main() {
    60     const int n=getint(),m=getint();
    61     for(register int i=1;i<=n;i++) {
    62         w[i]=getint();
    63     }
    64     for(register int i=1;i<n;i++) {
    65         add_edge(getint(),getint());
    66     }
    67     dfs(1,0);
    68     for(register int i=1;i<=n;i++) {
    69         t.modify(1,1,n,dfn[i],dfn[i]+size[i]-1,0,w[i]);
    70     }
    71     for(register int i=0;i<m;i++) {
    72         const int op=getint();
    73         if(op==1) {
    74             const int x=getint(),a=getint();
    75             t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,0,a);
    76         }
    77         if(op==2) {
    78             const int x=getint(),a=getint();
    79             t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,a,a-(int64)dep[x]*a);
    80         }
    81         if(op==3) {
    82             const int x=getint();
    83             printf("%lld
    ",t.query(1,1,n,x));
    84         }
    85     }
    86     return 0;
    87 }
    View Code

      同样还是一种将树“压扁”的方法。
      考虑我们之前讲过的括号序列。
      操作3中的询问相当于前缀和。 
      按照括号序列建线段树,操作1就变成了单点修改,操作2就变成了区间+a/-a。

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<vector>
     4 typedef long long int64;
     5 inline int getint() {
     6     register char ch;
     7     register bool neg=false;
     8     while(!isdigit(ch=getchar())) if(ch=='-') neg=true;
     9     register int x=ch^'0';
    10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    11     return neg?-x:x;
    12 }
    13 const int N=100001;
    14 int w[N],dfn[N],size[N],dep[N];
    15 std::vector<int> e[N];
    16 inline void add_edge(const int &u,const int &v) {
    17     e[u].push_back(v);
    18     e[v].push_back(u);
    19 }
    20 void dfs(const int &x,const int &par) {
    21     size[x]=1;
    22     dfn[x]=++dfn[0];
    23     dep[x]=dep[par]+1;
    24     for(unsigned i=0;i<e[x].size();i++) {
    25         const int &y=e[x][i];
    26         if(y==par) continue;
    27         dfs(y,x);
    28         size[x]+=size[y];
    29     }
    30 }
    31 class SegmentTree {
    32     #define _left <<1
    33     #define _right <<1|1
    34     private:
    35         int64 val1[N<<2],val2[N<<2];
    36     public:
    37         void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x,const int64 &y) {
    38             if(b==l&&e==r) {
    39                 val1[p]+=x;
    40                 val2[p]+=y;
    41                 return;
    42             }
    43             const int mid=(b+e)>>1;
    44             if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),x,y);
    45             if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,x,y);
    46         }
    47         int64 query(const int &p,const int &b,const int &e,const int &x) {
    48             int64 ret=val1[p]*dep[x]+val2[p];
    49             if(b==e) return ret;
    50             const int mid=(b+e)>>1;
    51             if(dfn[x]<=mid) ret+=query(p _left,b,mid,x);
    52             if(dfn[x]>mid) ret+=query(p _right,mid+1,e,x);
    53             return ret;
    54         }
    55     #undef _left
    56     #undef _right
    57 };
    58 SegmentTree t;
    59 int main() {
    60     //freopen("221/haoi2015_t21.in","r+",stdin);
    61     const int n=getint(),m=getint();
    62     for(register int i=1;i<=n;i++) {
    63         w[i]=getint();
    64     }
    65     for(register int i=1;i<n;i++) {
    66         add_edge(getint(),getint());
    67     }
    68     dfs(1,0);
    69     for(register int i=1;i<=n;i++) {
    70         t.modify(1,1,n,dfn[i],dfn[i]+size[i]-1,0,w[i]);
    71     }
    72     for(register int i=0;i<m;i++) {
    73         const int op=getint();
    74         if(op==1) {
    75             const int x=getint(),a=getint();
    76             t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,0,a);
    77         }
    78         if(op==2) {
    79             const int x=getint(),a=getint();
    80             t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,a,a-(int64)dep[x]*a);
    81         }
    82         if(op==3) {
    83             const int x=getint();
    84             printf("%lld
    ",t.query(1,1,n,x));
    85         }
    86     }
    87     return 0;
    88 }
    View Code
  • 相关阅读:
    rn 安卓开发报错
    rn 打包如果真机或者模拟机打包编译报错
    fluter 导航以及其他
    fluter 相关布局组件
    fluter 万事皆组件。常用组件
    rn开发问题简要
    app配置环境和打包方式以及其他问题
    小程序大概的开发流程
    ant-design-pro 开发 基于react 框架涉及到技术你的本地环境需要安装 yarn、node 和 git。我们的技术栈基于 ES2015+、React、UmiJS、dva、g2 和 antd,
    unity打包的webgl结合react使用
  • 原文地址:https://www.cnblogs.com/skylee03/p/8066974.html
Copyright © 2011-2022 走看看