首页 > 代码库 > COGS2608 [河南省队2016]无根树

COGS2608 [河南省队2016]无根树

传送门

这题大概就是传说中的动态树形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)$。

细节不是很多,当然愿意看代码也行。

技术分享
  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 }
View Code

 

COGS2608 [河南省队2016]无根树