[bzoj4182]Shopping

题目连接

暴力dp时间复杂度为$o(nm^{2})$,是不行的

考虑当我们强制该连通块包含根,可以直接在dfs序上dp,即若该点选则考虑从$f_{i+1}$转移,否则从其子树所对应区间右端点+1来转移(即$f_{dfn_{x}+sz_{x}}$),利用单调队列优化可做到$o(nm)$

之后对其点分治即可,时间复杂度为$o(nm\log_{2}n)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 505
 4 #define M 4005
 5 struct ji{
 6     int nex,to;
 7 }edge[N<<1];
 8 deque<int>q[M];
 9 int E,t,n,m,r,x,y,ans,w[N],c[N],d[N],head[N],vis[N],sz[N],dfn[N],f[N][M];
10 void add(int x,int y){
11     edge[E].nex=head[x];
12     edge[E].to=y;
13     head[x]=E++;
14 }
15 void tot(int k,int fa){
16     sz[k]=1;
17     for(int i=head[k];i!=-1;i=edge[i].nex)
18         if ((!vis[edge[i].to])&&(edge[i].to!=fa)){
19             tot(edge[i].to,k);
20             sz[k]+=sz[edge[i].to];
21         }
22 }
23 void find(int k,int fa,int s){
24     int mx=s-sz[k];
25     for(int i=head[k];i!=-1;i=edge[i].nex)
26         if ((!vis[edge[i].to])&&(edge[i].to!=fa)){
27             find(edge[i].to,k,s);
28             mx=max(mx,sz[edge[i].to]);
29         }
30     if (mx<=s/2)r=k;
31 }
32 void get_root(int k){
33     tot(k,0);
34     find(k,0,sz[k]);
35 }
36 void dfs(int k,int fa){
37     dfn[++dfn[0]]=k;
38     sz[k]=1;
39     for(int i=head[k];i!=-1;i=edge[i].nex)
40         if ((!vis[edge[i].to])&&(edge[i].to!=fa)){
41             dfs(edge[i].to,k);
42             sz[k]+=sz[edge[i].to];
43         }
44 }
45 void calc(int k){
46     dfn[0]=0;
47     dfs(k,0);
48     for(int i=0;i<=m;i++)f[dfn[0]+1][i]=0;
49     for(int i=dfn[0];i;i--){
50         int x=dfn[i];
51         for(int j=0;j<=m;j++)f[i][j]=f[i+sz[x]][j];
52         if (c[x]>m)continue;
53         for(int j=0;j<c[x];j++)q[j].clear();
54         for(int j=0;j<=m;j++){
55             int p=j%c[x];
56             while ((!q[p].empty())&&(q[p].front()<j-d[x]*c[x]))q[p].pop_front();
57             if (!q[p].empty()){
58                 int y=q[p].front();
59                 f[i][j]=max(f[i][j],f[i+1][y]+(j-y)/c[x]*w[x]);
60             }
61             while (!q[p].empty()){
62                 int y=q[p].back();
63                 if (f[i+1][y]+(j-y)/c[x]*w[x]>=f[i+1][j])break;
64                 q[p].pop_back();
65             }
66             q[p].push_back(j);
67         }
68     }
69     ans=max(ans,f[1][m]);
70 }
71 void dfs(int k){
72     if (vis[k])return;
73     get_root(k);
74     calc(r);
75     vis[r]=1;
76     for(int i=head[r];i!=-1;i=edge[i].nex)dfs(edge[i].to);
77 }
78 int main(){
79     scanf("%d",&t);
80     while (t--){
81         scanf("%d%d",&n,&m);
82         for(int i=1;i<=n;i++)scanf("%d",&w[i]);
83         for(int i=1;i<=n;i++)scanf("%d",&c[i]);
84         for(int i=1;i<=n;i++)scanf("%d",&d[i]);
85         E=ans=0;
86         memset(head,-1,sizeof(head));
87         for(int i=1;i<n;i++){
88             scanf("%d%d",&x,&y);
89             add(x,y);
90             add(y,x);
91         }
92         memset(vis,0,sizeof(vis));
93         dfs(1);
94         printf("%d\n",ans);
95     }
96 } 
View Code

 

posted @ 2021-01-23 16:43  PYWBKTDA  阅读(74)  评论(0编辑  收藏  举报