题目大意:给你一颗$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)$。

 #include<bits/stdc++.h>
#define ls (x<<1)
#define rs (x<<1|1)
#define mid ((a[x].l+a[x].r)>>1)
#define L long long
#define INF 1000000007
#define M 100005
using namespace std; struct edge{int u,next;}e[M*]={}; int head[M]={},use=;
void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;}
int val[M]={},n,m,f[M][]={}; int siz[M]={},son[M]={},dn[M]={},top[M]={},dfn[M]={},rec[M]={},fa[M]={},t=; void dfs1(int x){
siz[x]=;
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa[x]){
fa[e[i].u]=x;
dfs1(e[i].u);
siz[x]+=siz[e[i].u];
if(siz[son[x]]<siz[e[i].u]) son[x]=e[i].u;
}
}
void dfs2(int x,int Top){
top[x]=Top; dfn[x]=++t; rec[t]=x;
if(son[x]) dfs2(son[x],Top),dn[x]=dn[son[x]];
else dn[x]=x;
for(int i=head[x];i;i=e[i].next)
if(e[i].u!=fa[x]&&e[i].u!=son[x])
dfs2(e[i].u,e[i].u);
}
void dp(int x,int fa){
f[x][]=val[x];
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
dp(e[i].u,x);
f[x][]+=max(f[e[i].u][],f[e[i].u][]);
f[x][]+=f[e[i].u][];
}
} struct mat{
int a[][]; mat(){memset(a,,sizeof(a));}
mat(int x){a[][]=a[][]=a[][]=a[][]=x;}
mat(int a1,int a2,int a3,int a4){a[][]=a1; a[][]=a2; a[][]=a3; a[][]=a4;}
friend mat operator *(mat a,mat b){
mat c=-INF;
for(int i=;i<;i++)
for(int j=;j<;j++)
for(int k=;k<;k++)
c.a[i][j]=max(c.a[i][j],a.a[i][k]+b.a[k][j]);
return c;
}
}wei[M];
struct seg{int l,r;mat a;}a[M<<];
void pushup(int x){a[x].a=a[ls].a*a[rs].a;} void build(int x,int l,int r){
a[x].l=l; a[x].r=r;
if(l==r){
int u=rec[l],g0=,g1=val[u];
for(int i=head[u];i;i=e[i].next)
if(e[i].u!=son[u]&&e[i].u!=fa[u]){
g0+=max(f[e[i].u][],f[e[i].u][]);
g1+=f[e[i].u][];
}
a[x].a=wei[l]=mat(g0,g0,g1,-INF);
return;
}
build(ls,l,mid);
build(rs,mid+,r);
pushup(x);
}
void updata(int x,int k){
if(a[x].l==a[x].r) return void(a[x].a=wei[k]);
if(k<=mid) updata(ls,k);
else updata(rs,k);
pushup(x);
} mat query(int x,int l,int r){
if(l<=a[x].l&&a[x].r<=r) return a[x].a;
mat res;
if(l<=mid) res=query(ls,l,r);
if(mid<r){
if(l<=mid) return res*query(rs,l,r);
return query(rs,l,r);
}else return res;
}
mat query(int x){return query(,dfn[top[x]],dfn[dn[x]]);}
void solve(){mat hh=query(); printf("%d\n",max(hh.a[][],hh.a[][]));} void Updata(int x,int Val){
wei[dfn[x]].a[][]+=Val-val[x]; val[x]=Val;
while(x){ mat last=query(x);
int lg0=max(last.a[][],last.a[][]),lg1=last.a[][]; updata(,dfn[x]); mat now=query(x);
int ng0=max(now.a[][],now.a[][]),ng1=now.a[][]; x=fa[top[x]]; if(!x) return; int g0=ng0-lg0,g1=ng1-lg1;
wei[dfn[x]].a[][]+=g0;
wei[dfn[x]].a[][]+=g0;
wei[dfn[x]].a[][]+=g1;
}
} int main(){
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",val+i);
for(int i=,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs1();
dfs2(,);
dp(,);
build(,,n);
//solve();
while(m--){
int x,y; scanf("%d%d",&x,&y);
Updata(x,y);
solve();
}
}

【洛谷P4719】动态dp 动态dp模板的更多相关文章

  1. 洛谷 P5279 - [ZJOI2019]麻将(dp 套 dp)

    洛谷题面传送门 一道 dp 套 dp 的 immortal tea 首先考虑如何判断一套牌是否已经胡牌了,考虑 \(dp\)​​​​​.我们考虑将所有牌按权值大小从大到小排成一列,那我们设 \(dp_ ...

  2. 洛谷P4719 【模板】"动态 DP"&动态树分治

    [模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...

  3. 洛谷p1052过河 路径压缩+dp

    洛谷 P1052 过河 思路部分可以看这篇博客 我将在这里对其进行一些解释与补充 首先我们先看题 乍一看 这不是模板题吗 然后开开心心的敲了一个简单dp上去 #include<iostream& ...

  4. 洛谷2344 奶牛抗议(DP+BIT+离散化)

    洛谷2344 奶牛抗议 本题地址:http://www.luogu.org/problem/show?pid=2344 题目背景 Generic Cow Protests, 2011 Feb 题目描述 ...

  5. Lightning Conductor 洛谷P3515 决策单调性优化DP

    遇见的第一道决策单调性优化DP,虽然看了题解,但是新技能√,很开森. 先%FlashHu大佬,反正我是看了他的题解和精美的配图才明白的,%%%巨佬. 废话不多说,看题: 题目大意 已知一个长度为n的序 ...

  6. 洛谷P1541 乌龟棋(四维DP)

    To 洛谷.1541 乌龟棋 题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第N格是终点,游 ...

  7. 【洛谷】P1052 过河【DP+路径压缩】

    P1052 过河 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙 ...

  8. 【题解】洛谷P1052 [NOIP2005TG] 过河(DP+离散化)

    题目来源:洛谷P1052 思路 一开始觉得是贪心 但是仔细一想不对 是DP 再仔细一看数据不对 有点大 如果直接存下的话 显然会炸 那么就需要考虑离散化 因为一步最大跳10格 那么我们考虑从1到10都 ...

  9. 洛谷1736(二维dp+预处理)

    洛谷1387的进阶版,但很像. 1387要求是“全为1的正方形”,取dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1]))吧?这个有“只有对 ...

  10. bzoj3295 洛谷P3157、1393 动态逆序对——树套树

    题目:bzoj3295 https://www.lydsy.com/JudgeOnline/problem.php?id=3295 洛谷 P3157(同一道题) https://www.luogu.o ...

随机推荐

  1. 20155213 2016-2017-2 《Java程序设计》第八周学习总结

    20155213 2016-2017-2 <Java程序设计>第八周学习总结 教材学习内容总结 第十四章NIO与NIO2 NIO NIO使用频道来衔接数据节点,在处理数据时,NIO可以让你 ...

  2. 2018.10.08 NOIP模拟 斐波那契(贪心+hash/map)

    传送门 签到题. 显然是可以贪心分组的,也就是尽量跟当前的分成一组. 这时我们需要判断a[l]+a[r],a[l+1]+a[r]...a[r−1]+a[r]a[l]+a[r],a[l+1]+a[r]. ...

  3. 2018.09.28 牛客网contest/197/C期望操作数(状态转移+前缀和递推)

    传送门 比赛手动打了四项感觉有规律,调了40min+之后重新手算了后面几项发现只有前四项满足规律233. 首先这道题只跟q−xq-xq−x有关. 我们尝试找找递推关系. 我们令f[i]f[i]f[i] ...

  4. 2018.09.16 loj#10242. 取石子游戏 2(博弈论)

    传送门 同样有一个显然的结论. 如果a1a_1a1​ xorxorxor a2a_2a2​ xorxorxor a3a_3a3​ xor...xor...xor... xorxorxor ana_na ...

  5. Django介绍(3)

    https://www.cnblogs.com/yuanchenqi/articles/5786089.html

  6. java,arduino,C#之间的一些编码转换

    1.C#-> Encoding.UTF8.GetBytes( "abc中") ->[97,98,99,228,184,173] java->byte[] bs= ...

  7. UVaLive 4597 Inspection (网络流,最小流)

    题意:给出一张有向图,每次你可以从图中的任意一点出发,经过若干条边后停止,然后问你最少走几次可以将图中的每条边都走过至少一次,并且要输出方案,这个转化为网络流的话,就相当于 求一个最小流,并且存在下界 ...

  8. 用node.js写个在Bash上对字符串进行Base64或URL的encode和decode脚本

    一:自己这段时间经常要用到Base64编码和URL编码,写个编译型语言有点麻烦干脆就用node.js弄了个,弄好后在/etc/profile里加上alias就能完成工具的配置,先上代码: functi ...

  9. tred_extract_EDED_new

    # -*- coding:utf-8 -*- import re ''' 适应新版本 ''' year='17a'#用户自定义 ss='./data/'#根目录 filename = ss+'EDED ...

  10. hdu 1058

    这道题有很多种做法,但是思路大都是一样的,代码有点类似于poj2591这道题. 题意:问因子只含有2,3,5,7的第k个数是什么? #include<stdio.h> int f[5843 ...