【洛谷 3178】树上操作

题目描述

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:

  • 操作 1 :把某个节点 x 的点权增加 a 。
  • 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
  • 操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

输入输出格式

输入格式:

第一行包含两个整数 N, M 。表示点数和操作数。
接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, 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 。

 题解:树链泼粪,上代码

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
long long f[2001][2001];
struct line
{
     int s,t;
     long long x;
     int next;
}a[4001];
int head[2001];
long long tmp[2001];
int edge;
inline void add(int s,int t,long long x)
{
     a[edge].next=head[s];
     head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
     a[edge].x=x;
}
bool v[2001];
int size[2001];
int n,kk;
inline void trdp(int d)
{
     v[d]=true;
     size[d]=1;
     int i;
     int j,k;
     for(i=head[d];i!=0;i=a[i].next)
     {
          int t=a[i].t;
          if(!v[t])
          {
               trdp(t);
               for(j=0;j<=kk;j++)
                    tmp[j]=f[d][j];
               for(j=0;j<=min(size[d],kk);j++)
               {
                    for(k=0;k<=min(size[t],kk);k++)
                    {
                         if(j+k>kk)
                              break;
                         //int m=j+k;
                         tmp[j+k]=max(tmp[j+k],f[d][j]+f[t][k]+a[i].x*(k*(kk-k)+(size[t]-k)*(n-kk-(size[t]-k))));
                    }
               }
               size[d]+=size[t];
               for(j=0;j<=size[d];j++)
                    f[d][j]=max(f[d][j],tmp[j]);
          }
     }
}
int main()
{
     scanf("%d%d",&n,&kk);
     int i;
     int s,t;
     long long x;
     for(i=1;i<=n-1;i++)
     {
          scanf("%d%d%lld",&s,&t,&x);
          edge++;
          add(s,t,x);
          edge++;
          add(t,s,x);
     }
     trdp(1);
     printf("%lld\n",f[1][kk]);
     return 0; 
}

猜你喜欢

转载自www.cnblogs.com/wuhu-JJJ/p/11235260.html