bzoj5210最大连通子块和 (动态dp+卡常好题)

卡了一晚上,经历了被卡空间,被卡T,被卡数组等一堆惨惨的事情之后,终于在各位大爹的帮助下过了这个题qwqqq

(全网都没有用矩阵转移的动态dp,让我很慌张)

首先,我们先考虑一个比较基础的\(dp\)

我们令\(dp1[i]\)表示必须选\(i\)的最大连通块的权值是多少。

然后令\(ans1[i]\)表示\(i\)的子树中的\(dp1\)的最大值。

那么该怎么计算这两个数组呢。

首先$$dp1[i] = dp1[i]+max(0,dp1[p])$$ 其中\(p\)\(i\)的儿子。

\[ans1[i]=max(ans1[i],ans1[p]),ans1[i]=max(ans1[i],dp1[i]) \]

那么朴素的\(dp\)大概就是这样。
应该如何去优化呢。

由于是树上问题,不难想到树链剖分然后划分出轻重儿子。

我们令\(g\)表示考虑重儿子的\(dp\)数组,\(ans\)表示考虑重儿子的\(max\)数组。
然后\(f,ans1\)分别表示不考虑重儿子的\(dp和max\)数组。

\(p\)\(x\)的重儿子的话

不难发现,\(g[x]=max(f[x],g[p]+f[x]),ans[x]=max(ans1[x],max(ans[p],g[p]+f[x]))\)
我们这里默认\(ans1[x]\)一开始和\(f[x]\)取过\(max\).

那么我们就可以直接构造如下矩阵

f[x] f[x] -inf
-inf 0 -inf
f[x] ans1[x] 0

来进行转移(注意特判链尾)

但是有一个需要注意的地方,就是我们的\(ans1[x]\)由于涉及到修改,所以需要一个可删堆(或者\(multiset\)
来进行维护,感觉\(modify\)的时候还是有很多细节。qwq懒得写太多了,直接看代码吧。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]
#define rint register int 
using namespace std;
//char buf[100010],*buff = buf + 100000;

//#define getchar() (buff == buf + 100000 ? (fread(buf,1,100000,stdin),buff = buf) : 0,*buff++)

inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}
 
const int maxn = 2e5+1e2;
const int maxm = 2*maxn;
const ll inf = -1e15;
 
struct Node{
    priority_queue<ll> q1,q2;
    inline void push(ll x) {q1.push(x);}
    inline void erase(ll x) {q2.push(x);}
    inline ll top(){while ((!q2.empty()) && (q1.top()==q2.top())) q1.pop(),q2.pop(); return q1.top();}
};
 
Node ans[maxn];
 
struct Ju{
   int x,y;
   ll a[3][3];
   Ju operator * (Ju b)
   {
       Ju ans;
       ans.x=x;
       ans.y=b.y;
       for (rint i=0;i<=ans.x;++i)
       {
           for (rint j=0;j<=ans.y;++j) 
           {
		      ll uu = inf;
		      for (rint k=0;k<=y;++k)
                uu=max(uu,a[i][k]+b.a[k][j]);
              ans.a[i][j]=uu;
           }
       }
       return ans;
   }
};
 
int point[maxn],nxt[maxm],to[maxm];
int cnt,n,m;
int top[maxn],newnum[maxn],fa[maxn],son[maxn],size[maxn];
Ju f[4*maxn];
//Ju pre[maxn];
ll dp1[maxn],dp[maxn];
ll ans1[maxn];
int back[maxn];
int tot;
int tail[maxn];
ll val[maxn];
int leaf[maxn];
Ju caonima;

struct pp{
    ll cao,kao;
};
 
pp cnm[maxn];
 
inline void addedge(int x,int y)
{
    nxt[++cnt]=point[x];
    to[cnt]=y;
    point[x]=cnt;
}
 
inline void up(int root)
{
    f[root]=f[2*root+1]*f[2*root];
}
 
void build(int root,int l,int r)
{
    if (l==r)
    {
        int ymh = back[l];
         
        if (tail[top[ymh]]==ymh)
        {
            f[root].x=0;
            f[root].y=2;
            f[root].a[0][0]=dp[ymh];
            f[root].a[0][1]=max(dp[ymh],0ll);
        }
        else
        {   f[root].x=f[root].y=2;
            f[root].a[0][0]=dp[ymh];
            f[root].a[0][1]=dp[ymh];
            f[root].a[0][2]=inf;
            f[root].a[1][0]=inf;
            f[root].a[1][2]=inf;
            f[root].a[2][0]=dp[ymh];
            f[root].a[2][1]=ans[ymh].top();
        }
        leaf[ymh]=root;
        return;
    }
    int mid = l+r >> 1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    up(root);
}
 
void update(int root,int l,int r,int x)
{
    if (l==r)
    {
        f[root]=caonima;
        return;
    }
    int mid = l+r >> 1;
    if (x<=mid) update(root<<1,l,mid,x);
    else update(root<<1|1,mid+1,r,x);
    up(root);
}
 
Ju query(int root,int l,int r,int x,int y)
{
    if(x<=l && r<=y)
    {
        return f[root];
    }
    int mid = l+r >> 1;
    if (y<=mid) return query(root<<1,l,mid,x,y);
    if (x>mid) return query(root<<1|1,mid+1,r,x,y);
    return query(root<<1|1,mid+1,r,x,y)*query(root<<1,l,mid,x,y);
}
 
void dfs1(int x,int faa)
{
    size[x]=1;
    int maxson=-1;
    for (int i=point[x];i;i=nxt[i])
    {
        int p = to[i];
        if (p==faa) continue;
        fa[p]=x;
        dfs1(p,x);
        size[x]+=size[p];
        if (size[p]>maxson)
        {
            maxson=size[p];
            son[x]=p;
        }
    }
}
 
void dfs2(int x,int chain)
{
    top[x]=chain;
    tail[chain]=x;
    newnum[x]=++tot;
    back[tot]=x;
    if (!son[x]) return;
    dfs2(son[x],chain);
    for (int i=point[x];i;i=nxt[i])
    {
        int p = to[i];
        if (!newnum[p]) dfs2(p,p);
    }
}
 
void solve(int x,int fa)
{
    dp[x]=dp1[x]=val[x];
    ans1[x]=val[x];
    for (rint i=point[x];i;i=nxt[i])
    {
        int p = to[i];
        if (p==fa) continue;
        solve(p,x);
        dp1[x]=max(dp1[x],dp1[x]+dp1[p]);
        ans1[x]=max(ans1[x],ans1[p]);
        if (p!=son[x]) dp[x]=max(dp[x],dp[x]+dp1[p]),ans[x].push(ans1[p]);
    }
    ans[x].push(dp[x]);
    ans[x].push(0);
    //cout<<x<<endl;
    ans1[x]=max(ans1[x],dp1[x]);
    ans1[x]=max(ans1[x],0ll);
    //cout<<x<<endl;
}
 
void modify(int x,ll y)
{
    Ju tmp = f[leaf[x]];
    if (tail[top[x]]==x) 
    {
        tmp.a[0][0]+=y-val[x];
        tmp.a[0][1]=max(0ll,tmp.a[0][0]);
    }
    else
    {
        ans[x].erase(tmp.a[0][0]);
        tmp.a[0][0]+=y-val[x];
        tmp.a[0][1]=tmp.a[0][0];
        ans[x].push(tmp.a[0][0]);
        tmp.a[2][0]=tmp.a[0][0];
        tmp.a[2][1]=ans[x].top();
    }
    val[x]=y;
    caonima=tmp;
    update(1,1,n,newnum[x]);
    //cout<<x<<" "<<top[x]<<endl;
    for (rint now = top[x];now!=1;now=top[now])
    {
        //cout<<now<<endl;
        int faa = fa[now];
        //Ju ymh = query(1,1,n,newnum[faa],newnum[faa]);
        Ju ymh = f[leaf[faa]];
        Ju lyf;
        if (newnum[now]!=newnum[tail[top[now]]]) 
          lyf= query(1,1,n,newnum[now],newnum[tail[top[now]]]);
        else
          lyf = f[leaf[now]];
        ans[faa].erase(cnm[now].kao);
        ans[faa].erase(ymh.a[0][0]);
        ymh.a[0][0]+=max(lyf.a[0][0],0ll)-max(cnm[now].cao,0ll);
        ymh.a[0][1]=ymh.a[0][0];
        ymh.a[2][0]=ymh.a[0][0];
        ans[faa].push(ymh.a[0][0]);
        ans[faa].push(lyf.a[0][1]);
        ymh.a[2][1]=ans[faa].top();
        caonima=ymh;
        update(1,1,n,newnum[faa]);
        cnm[now].kao=lyf.a[0][1];
        cnm[now].cao=lyf.a[0][0];
        now=fa[now];
    }
}
 
int q;
char c;

signed main()
{
  //freopen("5210.in","r",stdin);
  //freopen("ymh.out","w",stdout);
  n=read(),q=read();
  //cout<<n<<" "<<q<<endl;
  for (rint i=1;i<=n;i++) val[i]=read();
  for (rint i=1;i<n;i++)
  {
      int x=read(),y=read();
      addedge(x,y);
      addedge(y,x);
  }
  dfs1(1,0);
  dfs2(1,1);
  solve(1,0);
  //cout<<1<<endl;
  build(1,1,n);
  //cout<<ans1[2]<<" "<<dp[2]<<" "<<dp1[2]<<endl;
  for (rint i=1;i<=n;++i)
  {
     Ju ymh = query(1,1,n,newnum[i],newnum[tail[top[i]]]);
     cnm[i].cao=ymh.a[0][0];
     cnm[i].kao=ymh.a[0][1];
  }
  for (rint i=1;i<=q;++i)
  {
      c=getchar();
      while (c<'A' || c>'Z') c=getchar();
      if (c=='M')
      {
         ll x=read(),y=read();
         modify(x,y);
      }
      else
      {
         int x=read();
         Ju ymh = query(1,1,n,newnum[x],newnum[tail[top[x]]]);
         cout<<max(ymh.a[0][1],max(ymh.a[0][0],0ll))<<"\n";
      }
  }
  return 0;
}
posted @ 2019-01-21 09:15  y_immortal  阅读(151)  评论(0编辑  收藏  举报