• 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))<<"
    ";
          }
      }
      return 0;
    }
    
  • 相关阅读:
    SQL 实现月度留存率/复购率
    Mac安装mysql数据库,并用navicat链接
    MAC电脑安装git
    form 表格提交
    幼稚从来都是相对的
    Vue 80端口无法使用,直接运行到1024问题
    iOS SDK framework 真机和模拟器合并步骤
    XCODE调试
    UN: Half of Refugee Children Do Not Go to School
    Vue界面传值逻辑
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10297080.html
Copyright © 2020-2023  润新知