洛谷——P3178 [HAOI2015]树上操作

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷——P3178 [HAOI2015]树上操作相关的知识,希望对你有一定的参考价值。

https://www.luogu.org/problem/show?pid=3178#sub

题目描述

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a 。操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

输入输出格式

输入格式:

 

第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

 

输出格式:

 

对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

 

输入输出样例

输入样例#1:
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
输出样例#1:
6
9
13

说明

对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不

会超过 10^6 。

 

树剖模板练习

  1 #include <algorithm>
  2 #include <cstdio>
  3 
  4 #define LL long long
  5 
  6 using namespace std;
  7 
  8 const LL N(100000+15);
  9 const LL M(100000+15);
 10 LL n,m,u,v,w,op,val[N];
 11 
 12 LL head[N],sumedge;
 13 struct Edge
 14 {
 15     LL u,v,next;
 16     Edge(LL u=0,LL v=0,LL next=0):
 17         u(u),v(v),next(next){}
 18 }edge[M<<1];
 19 inline void ins(LL u,LL v)
 20 {
 21     edge[++sumedge]=Edge(u,v,head[u]);
 22     head[u]=sumedge;
 23 }
 24 
 25 LL size[N],deep[N],dad[N],son[N],top[N],dfn[N],id[N],cnt;
 26 void DFS(LL x,LL father,LL deepth)
 27 {
 28     deep[x]=deepth;
 29     dad[x]=father;
 30     size[x]=1;
 31     for(LL i=head[x];i;i=edge[i].next)
 32     {
 33         LL v=edge[i].v;
 34         if(dad[x]==v) continue;
 35         DFS(v,x,deepth+1);
 36         size[x]+=size[v];
 37         if(size[son[x]]<size[v]) son[x]=v;
 38     }
 39 }
 40 void DFS_(LL x,LL Top)
 41 {
 42     top[x]=Top;
 43     id[x]=++cnt,dfn[cnt]=x;
 44     if(son[x]) DFS_(son[x],Top);
 45     for(LL i=head[x];i;i=edge[i].next)
 46     {
 47         LL v=edge[i].v;
 48         if(dad[x]!=v&&son[x]!=v) DFS_(v,v);
 49     }
 50 }
 51 
 52 struct Tree
 53 {
 54     LL l,r,mid,flag,val;
 55 }tree[N<<2];
 56 inline void Tree_up(LL now)
 57 {
 58     tree[now].val=tree[now<<1].val+tree[now<<1|1].val;
 59 }
 60 void Tree_down(LL now)
 61 {
 62     tree[now<<1].flag+=tree[now].flag;
 63     tree[now<<1].val+=(tree[now].mid-tree[now].l+1)*tree[now].flag;
 64     tree[now<<1|1].flag+=tree[now].flag;
 65     tree[now<<1|1].val+=(tree[now].r-tree[now].mid)*tree[now].flag;
 66     tree[now].flag=0;
 67 }
 68 void Tree_build(LL now,LL l,LL r)
 69 {
 70     tree[now].l=l;tree[now].r=r;
 71     if(l==r)
 72     {
 73         tree[now].val=val[dfn[l]];
 74         return ;
 75     }
 76     tree[now].mid=l+r>>1;
 77     Tree_build(now<<1,l,tree[now].mid);
 78     Tree_build(now<<1|1,tree[now].mid+1,r);
 79     Tree_up(now);
 80 }
 81 void Tree_change(LL now,LL l,LL r,LL x)
 82 {
 83     
 84     if(tree[now].l==l&&tree[now].r==r)
 85     {
 86         tree[now].flag+=x;
 87         tree[now].val+=(r-l+1)*x;
 88         return ;
 89     }
 90     if(tree[now].flag) Tree_down(now);
 91     if(tree[now].mid>=r) Tree_change(now<<1,l,r,x);
 92     else if(tree[now].mid<l) Tree_change(now<<1|1,l,r,x);
 93     else
 94     {
 95         Tree_change(now<<1,l,tree[now].mid,x);
 96         Tree_change(now<<1|1,tree[now].mid+1,r,x);
 97     }
 98     Tree_up(now);
 99 }
100 LL Tree_query(LL now,int l,int r)
101 {
102     if(tree[now].l==l&&tree[now].r==r)
103         return tree[now].val;
104     if(tree[now].flag) Tree_down(now);
105     if(tree[now].mid>=r) return Tree_query(now<<1,l,r);
106     else if(tree[now].mid<l) return Tree_query(now<<1|1,l,r);
107     else return Tree_query(now<<1,l,tree[now].mid)+Tree_query(now<<1|1,tree[now].mid+1,r);
108 }
109 
110 LL List_query(LL x,LL y)
111 {
112     LL ret=0;
113     for(;top[x]!=top[y];x=dad[top[x]])
114     {
115         if(deep[top[x]]<deep[top[y]]) swap(x,y);
116         ret+=Tree_query(1,id[top[x]],id[x]);
117     }
118     if(deep[x]<deep[y]) swap(x,y);
119     ret+=Tree_query(1,id[y],id[x]);
120     return ret;
121 }
122 
123 int if_,ch;
124 inline void read (LL &x)
125 {
126     if_=x=0;ch=getchar();
127     for(;ch<0||ch>9;ch=getchar())
128         if(ch==-) if_=1;
129     for(;ch>=0&&ch<=9;ch=getchar())
130         x=x*10+ch-0;
131     if(if_) x=(~x)+1;
132 }
133 
134 int main()
135 {
136     read(n); read(m);
137     for(LL i=1;i<=n;i++)
138         read(val[i]);
139     for(LL i=1;i<n;i++)
140     {
141         read(u); read(v);
142         ins(u,v),ins(v,u);
143     }
144     DFS(1,0,1);DFS_(1,1);
145     Tree_build(1,1,n);
146     for(;m--;)
147     {
148         read(op);
149         if(op==1)
150         {
151             read(u); read(w);
152             Tree_change(1,id[u],id[u],w);
153         }
154         else if(op==2)
155         {
156             read(u); read(w);
157             Tree_change(1,id[u],id[u]+size[u]-1,w);
158         }
159         else
160         {
161             read(u);
162             printf("%lld\n",List_query(u,1));
163         }
164     }
165     return 0;
166 }

 

以上是关于洛谷——P3178 [HAOI2015]树上操作的主要内容,如果未能解决你的问题,请参考以下文章

AC日记——[HAOI2015]树上操作 洛谷 P3178

洛谷 P3178 BZOJ 4034 [HAOI2015]树上操作

P3178 [HAOI2015]树上操作

P3178 [HAOI2015]树上操作

「Luogu P3178」[HAOI2015]树上操作

luogu P3178 [HAOI2015]树上操作 题解