luogu P4719 【模板】动态dp
noip怎么考这种东西啊。。。看错题场上爆零凉了
首先我们先进行树链剖分,那么问题可以转换成重链的答案+其他子节点的答案
而每次修改相当于改一段重链的答案,改一次其他子节点的答案交替进行
这样只有一个好处,就是把问题转换成序列问题,可以用线段树优化
fx,1表示不选当前点的最优解,fx,2表示选 方程很好列不写了
lx,1表示不选当前点,不管重儿子那边的最优解
为了加速我们转移套一个矩乘,(fx,1 fx,2)*(lx+1,1 lx+1,2 '\n' lx+1,1,0) = (fx+1,1,fx+1,2)
我们其实只需要求f1,1和f1,2 那么对于一条重链,我们得知了它最下面的点的新权值,我们可以通过把路径上的所有的点的转移矩阵乘上,得到最上面的点的值。因为树剖了,所以这个时候就是线段树派上用场了,注意新编号的大小要由深到浅从小到大,因为修改的时候是不断往上跳的
也就是可以得出一个这样的做法:对于每次修改,先通过该点重链的最下方的点结合新权值更新当前点,再用当前点更新重链头。此后就是重链头更新新的重链尾,重链尾更新他的重链头,不断循环直到根
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std; struct node
{
int x,y,next;
}a[];int len,last[];
void ins(int x,int y)
{
len++;
a[len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct Matrix
{
int mp[][];
Matrix(){memset(mp,-,sizeof(mp));}
Matrix(int A,int B,int C,int D)
{
memset(mp,-,sizeof(mp));
mp[][]=A,mp[][]=B,mp[][]=C,mp[][]=D;
}
friend Matrix operator *(Matrix a,Matrix b)
{
Matrix c;
memset(c.mp,-,sizeof(c.mp));
for(int i=;i<=;i++)
for(int j=;j<=;j++)
for(int k=;k<=;k++)
c.mp[i][j]=max(c.mp[i][j],a.mp[i][k]+b.mp[k][j]);
return c;
}
}f[],g[];//当前点答案,转移矩阵
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct trnode//用于求l~r的转移矩阵乘积(带修)
{
int l,r,lc,rc;
Matrix m;
}tr[];int trlen;
void tr_bt(int l,int r)
{
int now=++trlen;
tr[now].l=l;tr[now].r=r;
tr[now].lc=tr[now].rc=-;
tr[now].m=Matrix(,-(<<),-(<<),);
if(l<r)
{
int mid=(l+r)/;
tr[now].lc=trlen+;tr_bt(l,mid);
tr[now].rc=trlen+;tr_bt(mid+,r);
}
}
void tr_change(int now,int p,int x)
{
if(tr[now].l==tr[now].r){tr[now].m=g[x];return ;}
int mid=(tr[now].l+tr[now].r)/;
int lc=tr[now].lc,rc=tr[now].rc;
if(p<=mid)tr_change(lc,p,x);
else tr_change(rc,p,x);
tr[now].m=tr[lc].m*tr[rc].m;
}
Matrix tr_getmatrix(int now,int l,int r)
{
if(tr[now].l==l&&tr[now].r==r)return tr[now].m;
int mid=(tr[now].l+tr[now].r)/;
int lc=tr[now].lc,rc=tr[now].rc;
if(r<=mid) return tr_getmatrix(lc,l,r);
else if(mid+<=l)return tr_getmatrix(rc,l,r);
else return tr_getmatrix(lc,l,mid)*tr_getmatrix(rc,mid+,r);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //-------------------------------------------------struct---------------------------------------------------------------- int fa[],son[],tot[],dep[];
void pre_tree_node(int x)
{
tot[x]=,son[x]=;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa[x])
{
fa[y]=x;
dep[y]=dep[x]+;
pre_tree_node(y);
if(son[x]==||tot[son[x]]<tot[y])son[x]=y;
tot[x]+=tot[y];
}
}
}
int z,ys[];
int cnt,bel[],L[],R[];
void pre_tree_edge(int x,int wi)
{
ys[x]=++z;bel[x]=wi;
if(son[x]!=)pre_tree_edge(son[x],wi);
else R[wi]=x;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa[x]&&y!=son[x])
{
L[++cnt]=y;
pre_tree_edge(y,cnt);
}
}
}
void reverse()
{
for(int i=;i<=cnt;i++)
{
int ll=ys[L[i]],rr=ys[R[i]],now=R[i];
for(int j=ll;j<=rr;j++)ys[now]=j,now=fa[now];
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int w[];
void dfs(int x)
{
f[x].mp[][]=,f[x].mp[][]=w[x];
if(son[x]==)return ;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa[x])
{
dfs(y);
f[x].mp[][]+=max(f[y].mp[][],f[y].mp[][]);
f[x].mp[][]+=f[y].mp[][];
}
}
g[x].mp[][]=f[x].mp[][]-max(f[son[x]].mp[][],f[son[x]].mp[][]);
g[x].mp[][]=f[x].mp[][]-max(f[son[x]].mp[][],f[son[x]].mp[][]);
g[x].mp[][]=f[x].mp[][]-f[son[x]].mp[][];
g[x].mp[][]=-(<<);
tr_change(,ys[x],x);
} //-----------------------------------------------------init-------------------------------------------------------------------- Matrix tt;
void update(int y)
{
while(L[bel[y]]==y&&fa[y]!=)
{
int x=fa[y]; int d1=g[x].mp[][],d2=g[x].mp[][];
d1-=max(tt.mp[][],tt.mp[][]);
d2-=tt.mp[][];
d1+=max(f[y].mp[][],f[y].mp[][]);
d2+=f[y].mp[][]; g[x].mp[][]=g[x].mp[][]=d1;
g[x].mp[][]=d2;
tr_change(,ys[x],x); int u=R[bel[x]];tt=f[x];
f[x]=f[u]*tr_getmatrix(,ys[fa[u]],ys[x]); y=x;
}
}
void change(int x,int k)
{
if(L[bel[x]]==x)tt=f[x]; if(son[x]==)f[x].mp[][]+=-w[x]+k;
else
{
g[x].mp[][]+=-w[x]+k;
tr_change(,ys[x],x); int u=R[bel[x]];
f[x]=f[u]*tr_getmatrix(,ys[fa[u]],ys[x]);
} if(L[bel[x]]==x)update(x);
w[x]=k;
}
void solve(int x)
{
int tx=L[bel[x]];
while(x!=)
{
if(tx!=x)
{
tt=f[tx];
f[tx]=f[x]*tr_getmatrix(,ys[fa[x]],ys[tx]);
update(tx);
}
x=fa[tx],tx=L[bel[x]];
}
} //----------------------------------------------------solve-------------------------------------------------------------------- int main()
{
int n,Q,x,y;
scanf("%d%d",&n,&Q);
len=;memset(last,,sizeof(last));
for(int i=;i<=n;i++)scanf("%d",&w[i]);
for(int i=;i<n;i++)
{
scanf("%d%d",&x,&y);
ins(x,y),ins(y,x);
}
fa[]=,dep[]=;pre_tree_node();
z=,cnt=,L[]=;pre_tree_edge(,++cnt),reverse();
trlen=;tr_bt(,n);dfs(); while(Q--)
{
scanf("%d%d",&x,&y);
change(x,y);solve(x);
printf("%d\n",max(f[].mp[][],f[].mp[][]));
} return ;
}
luogu P4719 【模板】动态dp的更多相关文章
- [luogu 4719][模板]动态dp
传送门 Solution \(f_{i,0}\) 表示以i节点为根的子树内,不选i号节点的最大独立集 \(f_{i,1}\)表示以i节点为根的子树内,选i号节点的最大独立集 \(g_{i,0}\) 表 ...
- 【洛谷P4719】动态dp 动态dp模板
题目大意:给你一颗$n$个点的树,点有点权,有$m$次操作,每次操作给定$x$,$y$,表示修改点$x$的权值为$y$. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小. 数据范围:$n,m≤ ...
- [模板] 动态dp
用途 对于某些树形dp(目前只会树上最大权独立集或者类似的),动态地修改点权,并询问修改后的dp值 做法(树剖版) 以最大权独立集为例 设$f[x][0/1]$表示x选不选,这棵子树的最大权独立集大小 ...
- 洛谷4719 【模板】动态dp
题目:https://www.luogu.org/problemnew/show/P4719 关于动态DP似乎有猫锟的WC2018论文,但找不见:还是算了. http://immortalco.blo ...
- Luogu P4643 【模板】动态dp
题目链接 Luogu P4643 题解 猫锟在WC2018讲的黑科技--动态DP,就是一个画风正常的DP问题再加上一个动态修改操作,就像这道题一样.(这道题也是PPT中的例题) 动态DP的一个套路是把 ...
- 洛谷P4719 【模板】"动态 DP"&动态树分治
[模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...
- 洛谷P4719 【模板】动态dp(ddp LCT)
题意 题目链接 Sol 动态dp板子题.有些细节还没搞懂,待我研究明白后再补题解... #include<bits/stdc++.h> #define LL long long using ...
- P4719 【模板】动态dp
\(\color{#0066ff}{ 题目描述 }\) 给定一棵\(n\)个点的树,点带点权. 有\(m\)次操作,每次操作给定\(x,y\),表示修改点xx的权值为\(y\). 你需要在每次操作之后 ...
- 洛谷 P4719 【模板】动态dp【动态dp】
是动态dp的板子 大致思想就是用g[u]来表示不包含重链转移的dp值,然后用线段树维护重链,这样线段树的根就相当于这条重链的top的真实dp值 每次修改的时候,修改x点会影响到x到根的真实dp值,但是 ...
- P4719 【模板】"动态 DP"&动态树分治
题目描述 给定一棵 n 个点的树,点带点权. 有 m 次操作,每次操作给定 x,y,表示修改点 x 的权值为 y. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小. 输入格式 第一行有两个整数 ...
随机推荐
- Python随笔day01
环境变量的配置: 配置Python的安装目录到path变量中,例如C:\Python37 标识符的命名规则: 变量名只能以数字,字母,下划线组成. 不能以数字开头,保留字不能被使用. 建议使用下划线分 ...
- Vue如何在data中正常引入图片路径
在Vue项目中通过data设置图片路径,然后在template中引入后页面无法显示图片,浏览器控制台报错: 刚开始以为是路径出问题了,于是绝对路径.相对路 ...
- python 爬虫示例,方便日后参考
参考网址:https://zhuanlan.zhihu.com/p/32037625 def getOneMoviesInfo(Mid,url): import requests from lxml ...
- 56. spring boot中使用@Async实现异步调用【从零开始学Spring Boot】
什么是"异步调用"? "异步调用"对应的是"同步调用",同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执 ...
- 【判断二分图】C. Catch
https://www.bnuoj.com/v3/contest_show.php?cid=9154#problem/C [题意] 给定一个无向图,给定小偷的起始位置 从这个起始位置开始,小偷可以在单 ...
- 【莫比乌斯反演+树状数组+分块求和】GCD Array
https://www.bnuoj.com/v3/contest_show.php?cid=9149#problem/I [题意] 给定长度为l的一个数组,初始值为0:规定了两种操作: [思路] 找到 ...
- Flask(4):wtforms组件 & 数据库连接池 DBUtils
wtforms 组件的作用: --- 生成 HTML 标签 --- form 表单验证 示例代码: app.py from flask import Flask, render_template, r ...
- 被老板逼着实现了Excle的透视表分析算法
package com.example.demo; import java.sql.SQLException;import java.util.ArrayList;import java.util.H ...
- 洛谷—— P3386 【模板】二分图匹配
P3386 [模板]二分图匹配(复习) 题目背景 二分图 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式: 第一行,n,m,e 第二至e+1行,每 ...
- 洛谷 P1404 平均数
P1404 平均数 题目描述 给一个长度为n的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度>=m. 输入输出格式 输入格式: N+1行, 第一行两个整数n和m 接下来n ...