[HAOI2015]树上操作

【题目描述】

有一棵点数为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)。

【输出格式】

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

【样例输入】

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

【样例输出】

6

9

13

【提示】

对于30%的数据,N,M<=1000

对于50%的数据,N,M<=100000且数据随机。

对于100%的数据,N,M<=100000,且所有输入数据的绝对值都不会超过10^6。

 

很有思考性的题,所以贴出来。

题解链接:http://www.cnblogs.com/Asm-Definer/p/4466729.html 

1操作直接在BIT 操作,

 

还要读入挂,OI真辛苦

  1 #include<stdio.h>
  2 #include<algorithm>
  3 #include<math.h>
  4 #include<vector>
  5 #include< string.h>
  6 #include< string>
  7 #include< set>
  8 #include<iostream>
  9  using  namespace std;
 10 typedef  long  long ll;
 11  #define N 153333
 12 
 13 vector< int>mp[N];
 14  int a[N],dep[N],st[N],ed[N],tot= 1;
 15 ll f1[N],f2[N],c[N];
 16  int head[N];
 17  struct node
 18 {
 19      int v,next;
 20 }e[N<< 1];
 21  int n,m;
 22  int lowbit( int x)
 23 {
 24      return x&-x;
 25 }
 26 
 27  void add1( int x,ll v)
 28 {
 29      for ( int i=x;i<=n;i+=lowbit(i)) f1[i]+=v;
 30 }
 31  void add2( int x,ll v)
 32 {
 33      for ( int i=x;i<=n;i+=lowbit(i)) f2[i]+=v;
 34 }
 35 ll query1( int x)
 36 {
 37     ll s= 0;
 38      for ( int i=x;i> 0;i-=lowbit(i))
 39         s+=f1[i];
 40      return s;
 41 }
 42 ll query2( int x)
 43 {
 44     ll s= 0;
 45      for ( int i=x;i> 0;i-=lowbit(i))
 46         s+=f2[i];
 47      return s;
 48 }
 49 
 50  void dfs( int u, int pre, int t,ll sum)
 51 {
 52     st[u]=tot++;
 53     dep[u]=t;
 54     sum+=a[u];
 55     c[u]=sum;
 56      for ( int i=head[u];i!=- 1;i=e[i].next)
 57     {
 58          int v=e[i].v;
 59          if (v==pre)  continue;
 60         dfs(v,u,t+ 1,sum);
 61     }
 62     ed[u]=tot- 1;
 63 }
 64  void judge()
 65 {
 66     freopen( " haoi2015_t2.in ", " r ",stdin);
 67     freopen( " haoi2015_t2.out ", " w ",stdout);
 68 
 69 }
 70  int tt;
 71  void add( int u, int v)
 72 {
 73     e[tt].v=v;
 74     e[tt].next=head[u];
 75     head[u]=tt++;
 76 }
 77 
 78  void Getz( int &x){
 79      int ch;
 80      while(ch=getchar(),ch< 48||ch> 57);x=ch- 48;
 81      while(ch=getchar(),ch> 47&&ch< 58) x=x* 10+ch- 48;
 82 }
 83  int main()
 84 {
 85     judge();
 86     tt= 0;
 87     memset(head,- 1, sizeof(head));
 88      // scanf("%d%d",&n,&m);
 89      Getz(n); 
 90     Getz(m);
 91      for ( int i= 1;i<=n;i++) Getz(a[i]);
 92      for ( int i= 1;i<n;i++)
 93     {
 94          int x,y;
 95         //  scanf("%d%d",&x,&y);
 96          Getz(x); Getz(y);
 97          // mp[x].push_back(y);
 98          add(x,y);
 99         add(y,x);
100          // mp[y].push_back(x);
101      }
102     dfs( 1,- 1, 1, 0);
103  //     for (int i=1;i<=n;i++)
104     //       cout<<st[i]<<" "<<ed[i]<<endl;
105 
106      while (m--)
107     {
108          int op,u,v;
109         scanf( " %d ",&op);
110          if (op== 1)
111         {
112              // scanf("%d%d",&u,&v);
113              Getz(u); Getz(v);
114             add2(st[u],v);add2(ed[u]+ 1,-v);
115         } else  if (op== 2)
116         {
117              //  scanf("%d%d",&u,&v);
118               Getz(u); Getz(v);
119              ll tmp= 1-dep[u];
120              tmp*=v;
121              add1(st[u],v),add1(ed[u]+ 1,-v);
122              add2(st[u],tmp),add2(ed[u]+ 1,-tmp);
123         }
124          else
125         {
126               // scanf("%d",&u);
127               Getz(u);
128              printf( " %lld\n ",c[u]+query1(st[u])*dep[u]+query2(st[u]));
129         }
130     }
131 
132      return  0;

133 } 

转载于:https://www.cnblogs.com/forgot93/p/4847732.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值