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的更多相关文章

  1. [luogu 4719][模板]动态dp

    传送门 Solution \(f_{i,0}\) 表示以i节点为根的子树内,不选i号节点的最大独立集 \(f_{i,1}\)表示以i节点为根的子树内,选i号节点的最大独立集 \(g_{i,0}\) 表 ...

  2. 【洛谷P4719】动态dp 动态dp模板

    题目大意:给你一颗$n$个点的树,点有点权,有$m$次操作,每次操作给定$x$,$y$,表示修改点$x$的权值为$y$. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小. 数据范围:$n,m≤ ...

  3. [模板] 动态dp

    用途 对于某些树形dp(目前只会树上最大权独立集或者类似的),动态地修改点权,并询问修改后的dp值 做法(树剖版) 以最大权独立集为例 设$f[x][0/1]$表示x选不选,这棵子树的最大权独立集大小 ...

  4. 洛谷4719 【模板】动态dp

    题目:https://www.luogu.org/problemnew/show/P4719 关于动态DP似乎有猫锟的WC2018论文,但找不见:还是算了. http://immortalco.blo ...

  5. Luogu P4643 【模板】动态dp

    题目链接 Luogu P4643 题解 猫锟在WC2018讲的黑科技--动态DP,就是一个画风正常的DP问题再加上一个动态修改操作,就像这道题一样.(这道题也是PPT中的例题) 动态DP的一个套路是把 ...

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

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

  7. 洛谷P4719 【模板】动态dp(ddp LCT)

    题意 题目链接 Sol 动态dp板子题.有些细节还没搞懂,待我研究明白后再补题解... #include<bits/stdc++.h> #define LL long long using ...

  8. P4719 【模板】动态dp

    \(\color{#0066ff}{ 题目描述 }\) 给定一棵\(n\)个点的树,点带点权. 有\(m\)次操作,每次操作给定\(x,y\),表示修改点xx的权值为\(y\). 你需要在每次操作之后 ...

  9. 洛谷 P4719 【模板】动态dp【动态dp】

    是动态dp的板子 大致思想就是用g[u]来表示不包含重链转移的dp值,然后用线段树维护重链,这样线段树的根就相当于这条重链的top的真实dp值 每次修改的时候,修改x点会影响到x到根的真实dp值,但是 ...

  10. P4719 【模板】"动态 DP"&动态树分治

    题目描述 给定一棵 n 个点的树,点带点权. 有 m 次操作,每次操作给定 x,y,表示修改点 x 的权值为 y. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小. 输入格式 第一行有两个整数 ...

随机推荐

  1. 笔试算法题(50):简介 - 广度优先 & 深度优先 & 最小生成树算法

    广度优先搜索&深度优先搜索(Breadth First Search & Depth First Search) BFS优缺点: 同一层的所有节点都会加入队列,所以耗用大量空间: 仅能 ...

  2. Python 函数递归-三元表达式-列表生成式-字典生成式-匿名函数-内置函数

    上节课复习: 1. 无参装饰器 def 装饰器名字(func): def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res ...

  3. Codeforces Round #413 B T-shirt buying (STL set)

    链接:http://codeforces.com/contest/799/problem/B 题意: 给定n件衣服,对于第i(1<i<=n)件衣服,分别有价格pi,前颜色ai,后颜色bi三 ...

  4. UVA 10652 凸包问题

    #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> # ...

  5. hdu 4033 状态压缩枚举

    /* 看别人的的思路 搜索搜不出来我太挫了 状态压缩枚举+好的位置 */ #include<stdio.h> #include<string.h> #define N 20 i ...

  6. bzoj 1049 [HAOI2006]数字序列

    [bzoj1049][HAOI2006]数字序列 Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不 ...

  7. 【HDOJ6146】Pokémon GO(DP,计数)

    题意:一个2*n的矩阵,从任意一格出发,不重复且不遗漏地走遍所有格子,问方案数 mo 10^9+7 n<=10000 思路:因为OEIS搜出来的两个数列都是错误的,所以考虑DP 设B[i]为2* ...

  8. Jquery判断某个字符串是否在数组中

    使用$.inArray方法判断,如果存在则返回0,不存在返回-1,结果如下: 另外也可以将数组转为字符串,并使用正则表达式处理

  9. 2.4 选择第k大的元素 selection

    1.目标:找到N个元素中,第k大的数. 例如:max是k=N--1:min是k=0:median是k=N/2 2.Quick-select 借鉴了快速排序的思想 (1)利用partition保证: ① ...

  10. 用jQuery向div中添加Html文本内容

    前台代码: <link href="http://www.cnblogs.com/Content/themes/base/jquery-ui.css" rel="s ...