这题大概就是传说中的动态树形DP了吧,学习了一波……
首先,对于没有修改的情况,不难想到树形DP,定义$f_i$表示强制必须选$i$且只能再选$i$的子树中的点的最优解,易得转移方程$f_i=\sum_{j是i的儿子}\max\{f_j,0\}+w_i$,最终答案即为$\max\{f_i\}$。
现在我们不仅需要求出答案,还要在每次修改之后快速计算新的答案。借鉴陈俊锟的论文,可以用树剖来做这道题,那么我们只需要对每条链动态维护答案即可,最后用一个全局堆维护每条链的答案就可以了。
我们可以重新定义$f_i$表示只考虑$i$以及轻边连出去的子树的最优解,并用线段树维护重链,不难看出每条链的答案就是链上所有点的$f$值的最大子段和。那么直接用线段树维护最大子段和即可,预处理$O(n)$,单次修改$O(\log^2 n)$,查询$O(1)$。
细节不是很多,当然愿意看代码也行。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=100010; 8 struct binary_heap{ 9 priority_queue<int>q1,q2; 10 binary_heap(){} 11 void push(int x){q1.push(x);} 12 void erase(int x){q2.push(x);} 13 int top(){ 14 while(!q2.empty()&&q1.top()==q2.top()){ 15 q1.pop(); 16 q2.pop(); 17 } 18 return q1.top(); 19 } 20 }heap; 21 void dfs1(int); 22 void dfs2(int); 23 void modify(int,int); 24 void build(int,int,int&); 25 void modify(int,int,int); 26 void refresh(int); 27 vector<int>G[maxn]; 28 int sum[maxn<<2],maxsum[maxn<<2],prefix[maxn<<2],suffix[maxn<<2],lc[maxn<<2],rc[maxn<<2],root[maxn],cnt=0; 29 int p[maxn],size[maxn],d[maxn],dfn[maxn],finish[maxn],tim=0,son[maxn],top[maxn],len[maxn]; 30 int f[maxn],a[maxn],w[maxn]; 31 int n,m,t,k; 32 int main(){ 33 freopen("nortree.in","r",stdin); 34 freopen("nortree.out","w",stdout); 35 int __size__=128<<20; 36 char *__p__=(char*)malloc(__size__)+__size__; 37 __asm__("movl %0, %%esp\n"::"r"(__p__)); 38 scanf("%d%d",&n,&m); 39 for(int i=1;i<=n;i++)scanf("%d",&w[i]); 40 for(int i=1,x,y;i<n;i++){ 41 scanf("%d%d",&x,&y); 42 G[x].push_back(y); 43 G[y].push_back(x); 44 } 45 dfs1(1); 46 dfs2(1); 47 while(m--){ 48 int d; 49 scanf("%d",&d); 50 if(d==1){ 51 int x,z; 52 scanf("%d%d",&x,&z); 53 modify(x,z); 54 } 55 else printf("%d\n",heap.top()); 56 } 57 return 0; 58 } 59 void dfs1(int x){ 60 size[x]=1; 61 d[x]=d[p[x]]+1; 62 for(int i=0;i<(int)G[x].size();i++)if(G[x][i]!=p[x]){ 63 p[G[x][i]]=x; 64 dfs1(G[x][i]); 65 size[x]+=size[G[x][i]]; 66 if(size[G[x][i]]>size[son[x]])son[x]=G[x][i]; 67 } 68 } 69 void dfs2(int x){ 70 if(x==son[p[x]])top[x]=top[p[x]]; 71 else top[x]=x; 72 dfn[x]=++tim; 73 f[x]=w[x]; 74 if(son[x])dfs2(son[x]); 75 for(int i=0;i<(int)G[x].size();i++)if(G[x][i]!=p[x]&&G[x][i]!=son[x]){ 76 dfs2(G[x][i]); 77 f[x]+=max(prefix[root[G[x][i]]],0); 78 } 79 finish[x]=tim; 80 if(top[x]==x){ 81 int cnt=0,y=x; 82 while(y){ 83 a[++cnt]=f[y]; 84 y=son[y]; 85 } 86 len[x]=cnt; 87 build(1,len[x],root[x]); 88 heap.push(maxsum[root[x]]); 89 } 90 } 91 void modify(int x,int z){ 92 f[x]+=z-w[x]; 93 w[x]=z; 94 while(x){ 95 if(p[top[x]])f[p[top[x]]]-=prefix[root[top[x]]]; 96 heap.erase(maxsum[root[top[x]]]); 97 t=d[x]-d[top[x]]+1; 98 k=f[x]; 99 modify(1,len[top[x]],root[top[x]]); 100 if(p[top[x]])f[p[top[x]]]+=prefix[root[top[x]]]; 101 heap.push(maxsum[root[top[x]]]); 102 x=p[top[x]]; 103 } 104 } 105 void build(int l,int r,int &rt){ 106 rt=++cnt; 107 if(l==r){ 108 sum[rt]=a[l]; 109 maxsum[rt]=prefix[rt]=suffix[rt]=max(a[l],0); 110 return; 111 } 112 int mid=(l+r)>>1; 113 build(l,mid,lc[rt]); 114 build(mid+1,r,rc[rt]); 115 refresh(rt); 116 } 117 void modify(int l,int r,int rt){ 118 if(l==r){ 119 sum[rt]=k; 120 maxsum[rt]=prefix[rt]=suffix[rt]=max(k,0); 121 return; 122 } 123 int mid=(l+r)>>1; 124 if(t<=mid)modify(l,mid,lc[rt]); 125 else modify(mid+1,r,rc[rt]); 126 refresh(rt); 127 } 128 void refresh(int rt){ 129 sum[rt]=sum[lc[rt]]+sum[rc[rt]]; 130 maxsum[rt]=max(max(maxsum[lc[rt]],maxsum[rc[rt]]),suffix[lc[rt]]+prefix[rc[rt]]); 131 prefix[rt]=max(prefix[lc[rt]],sum[lc[rt]]+prefix[rc[rt]]); 132 suffix[rt]=max(suffix[rc[rt]],sum[rc[rt]]+suffix[lc[rt]]); 133 }