zoukankan      html  css  js  c++  java
  • 【洛谷P4719】动态dp 动态dp模板

    题目大意:给你一颗$n$个点的树,点有点权,有$m$次操作,每次操作给定$x$,$y$,表示修改点$x$的权值为$y$

    你需要在每次操作之后求出这棵树的最大权独立集的权值大小。

    数据范围:$n,m≤1e5$

    我们显然可以得出一个$O(nm)$的暴力做法,每次修改完后$dp$一次,然而这个显然会超时。

    考虑当树退化成链时的简单做法。

    我们用线段树维护每个区间的答案。对于区间$[l,r]$,我们维护一个$2×2$的答案矩阵$ans$。

    设$ans[0][0]$表示区间左端点可能被选择,右端点一定不被选择时的最大值。

    设$ans[0][1]$表示区间左端点可能被选择,右端点可能被选择时的最大值。

    设$ans[1][0]$表示区间左端点一定不被选择,右端点一定不被选择时的最大值。

    设$ans[1][1]$表示区间左端点一定不被选择,右端点可能被选择时的最大值。

    对于叶节点,显然$ans[0][0]=ans[0][1]=0$,$ans[1][0]=val[x]$,$ans[1][1]=-INF$。

    考虑已经求出$[l,mid]$,$[mid+1,r]$两个区间的答案,如何合并出$[l,r]$的答案。

    不难发现$ans[0][0]=max(ansl[0][0]+ansr[0][0],ansl[0][1]+ansr[1][0])$;

    $ans[0][1],ans[1][0],ans[1][1]$的转移都长得差不多。

    每次修改一个权值,我们可以通过$pushup$更新区间的答案矩阵。

    考虑把这个做法扩展到树上,我们通过树链剖分将整棵树剖成若干条链,对于每一条链我们就用如上所述的方式进行维护。对于接有轻儿子的链上节点,我们将轻儿子产生的共吸纳累计,将其加到链上节点上即可。

    (细节可以看代码)

    时间复杂度:$O(m log^2n)$。

      1 #include<bits/stdc++.h>
      2 #define ls (x<<1)
      3 #define rs (x<<1|1)
      4 #define mid ((a[x].l+a[x].r)>>1)
      5 #define L long long
      6 #define INF 1000000007
      7 #define M 100005
      8 using namespace std;
      9 
     10 struct edge{int u,next;}e[M*2]={0}; int head[M]={0},use=0;
     11 void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;}
     12 int val[M]={0},n,m,f[M][2]={0};
     13 
     14 int siz[M]={0},son[M]={0},dn[M]={0},top[M]={0},dfn[M]={0},rec[M]={0},fa[M]={0},t=0;
     15 
     16 void dfs1(int x){
     17     siz[x]=1;
     18     for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa[x]){
     19         fa[e[i].u]=x;
     20         dfs1(e[i].u);
     21         siz[x]+=siz[e[i].u];
     22         if(siz[son[x]]<siz[e[i].u]) son[x]=e[i].u;
     23     }
     24 }
     25 void dfs2(int x,int Top){
     26     top[x]=Top; dfn[x]=++t; rec[t]=x;
     27     if(son[x]) dfs2(son[x],Top),dn[x]=dn[son[x]];
     28     else dn[x]=x;
     29     for(int i=head[x];i;i=e[i].next) 
     30     if(e[i].u!=fa[x]&&e[i].u!=son[x])
     31     dfs2(e[i].u,e[i].u);
     32 }
     33 void dp(int x,int fa){
     34     f[x][1]=val[x];
     35     for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
     36         dp(e[i].u,x);
     37         f[x][0]+=max(f[e[i].u][0],f[e[i].u][1]);
     38         f[x][1]+=f[e[i].u][0];
     39     }
     40 }
     41 
     42 struct mat{
     43     int a[2][2]; mat(){memset(a,0,sizeof(a));}
     44     mat(int x){a[0][0]=a[0][1]=a[1][0]=a[1][1]=x;}
     45     mat(int a1,int a2,int a3,int a4){a[0][0]=a1; a[0][1]=a2; a[1][0]=a3; a[1][1]=a4;}
     46     friend mat operator *(mat a,mat b){
     47         mat c=-INF;
     48         for(int i=0;i<2;i++)
     49         for(int j=0;j<2;j++)
     50         for(int k=0;k<2;k++)
     51         c.a[i][j]=max(c.a[i][j],a.a[i][k]+b.a[k][j]);
     52         return c;
     53     }
     54 }wei[M];
     55 struct seg{int l,r;mat a;}a[M<<2];
     56 void pushup(int x){a[x].a=a[ls].a*a[rs].a;}
     57 
     58 void build(int x,int l,int r){
     59     a[x].l=l; a[x].r=r;
     60     if(l==r){
     61         int u=rec[l],g0=0,g1=val[u];
     62         for(int i=head[u];i;i=e[i].next)
     63         if(e[i].u!=son[u]&&e[i].u!=fa[u]){
     64             g0+=max(f[e[i].u][0],f[e[i].u][1]);
     65             g1+=f[e[i].u][0];
     66         }
     67         a[x].a=wei[l]=mat(g0,g0,g1,-INF);
     68         return;
     69     }
     70     build(ls,l,mid);
     71     build(rs,mid+1,r);
     72     pushup(x);
     73 }
     74 void updata(int x,int k){
     75     if(a[x].l==a[x].r) return void(a[x].a=wei[k]);
     76     if(k<=mid) updata(ls,k);
     77     else updata(rs,k);
     78     pushup(x);
     79 }
     80 
     81 mat query(int x,int l,int r){
     82     if(l<=a[x].l&&a[x].r<=r) return a[x].a;
     83     mat res;
     84     if(l<=mid) res=query(ls,l,r);
     85     if(mid<r){
     86         if(l<=mid) return res*query(rs,l,r);
     87         return query(rs,l,r);
     88     }else return res;
     89 }
     90 mat query(int x){return query(1,dfn[top[x]],dfn[dn[x]]);}
     91 void solve(){mat hh=query(1); printf("%d
    ",max(hh.a[0][0],hh.a[1][0]));}
     92 
     93 void Updata(int x,int Val){
     94     wei[dfn[x]].a[1][0]+=Val-val[x]; val[x]=Val;
     95     while(x){
     96         
     97         mat last=query(x);
     98         int lg0=max(last.a[0][0],last.a[1][0]),lg1=last.a[0][0];
     99         
    100         updata(1,dfn[x]);
    101         
    102         mat now=query(x);
    103         int ng0=max(now.a[0][0],now.a[1][0]),ng1=now.a[0][0];
    104         
    105         x=fa[top[x]]; if(!x) return;
    106         
    107         int g0=ng0-lg0,g1=ng1-lg1;
    108         wei[dfn[x]].a[0][0]+=g0; 
    109         wei[dfn[x]].a[0][1]+=g0;
    110         wei[dfn[x]].a[1][0]+=g1;
    111     }
    112 }
    113 
    114 int main(){
    115     //freopen("in.txt","r",stdin);
    116     scanf("%d%d",&n,&m);
    117     for(int i=1;i<=n;i++) scanf("%d",val+i);
    118     for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
    119     dfs1(1);
    120     dfs2(1,1);
    121     dp(1,0);
    122     build(1,1,n);
    123     //solve();
    124     while(m--){
    125         int x,y; scanf("%d%d",&x,&y);
    126         Updata(x,y);    
    127         solve();
    128     }
    129 }
  • 相关阅读:
    实验4-2-4 换硬币 (20分)
    实验4-1-4 求整数的位数及各位数字之和 (15分)
    实验4-1-10 兔子繁衍问题 (15分)
    实验4-1-7 特殊a串数列求和 (20分)
    实验4-1-3 找出最小值 (20分)
    实验4-1-2 求奇数和 (15分)
    实验4-1-1 最大公约数和最小公倍数 (15分)emmm辗转相除法
    实验3-10 高速公路超速处罚 (15分)
    1.使用Lucene开发自己的搜索引擎--倒排索引基础知识
    办公自动化项目从无到有-第三篇系统管理模块
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10321714.html
Copyright © 2011-2022 走看看