1. 程式人生 > >COGS2608 [河南省隊2016]無根樹

COGS2608 [河南省隊2016]無根樹

維護 pre oot closed 最大子段和 情況 src string 分享

傳送門

這題大概就是傳說中的動態樹形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]無根樹