在进入正文以前,我想先哭一下。
嘤嘤嘤嘤嘤嘤嘤
嘤嘤嘤嘤嘤嘤嘤
嘤嘤嘤我嘤嘤嘤
嘤嘤嘤嘤嘤嘤嘤
嘤嘤嘤嘤嘤嘤嘤
事实上在NOIP2018以前,我看到过动态dp的课件,然后觉得看起来很有意思。
但是我竟然没有仔细去看!没有仔细去看!。。。
内心:NOIP肯定不会考这种东西呀orz......(flag)
然后NOIP2018day2T3就是动态dp裸题。
呵呵呵呵呵呵呵。。。
动态dp:
给你一个很普通的序列上或者树上的dp。然后要支持边(通常单点)修改边询问。。。
事实上有些dp很鬼畜啊。。f[i][0],f[i][1],g[i][0],g[i][1]。。。
于是我们可以把它们的转移存成矩阵,这样会方便很多。
如果是在序列上,相当于单点修改求区间乘积,就是个线段树。
如果是在树上,就加个树链剖分。
然后树剖还可以被称作链分治,事实上它在这里叫这个名字可能更好吧orz。
往往你可以设g[i]表示i的轻儿子对f[i]的贡献。
每次单点修改时,由于它到根的路径上重链不超过logn条,只要暴力修改这些重链底端点的g就可以了。
查询时,相当于查询这个点到它所在重链底端的那段区间。也是线段树即可。
例题:
luogu4719
#include<bits/stdc++.h>
using namespace std;
#define rep(x,y,z) for (int x=y; x<=z; x++)
#define downrep(x,y,z) for (int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define LL long long
#define repedge(x,y) for (int x=hed[y]; ~x; x=edge[x].nex)
inline int read(){
int x=0; int w=0; char ch=0;
while (ch<'0' || ch>'9') w|=ch=='-',ch=getchar();
while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return w? -x:x;
}
const int N=100005;
int n,m,w[N],fa[N],top[N],dep[N],tin[N],tout[N],dw[N],tot,nedge,hed[N],sz[N],son[N];
struct Edge{ int to,nex; }edge[N<<1];
struct mat{
int num[2][2];
void init(){ ms(num,0,num); }
void one(){ init(); rep(i,0,1) num[i][i]=1; }
}g[N],f[N],tr[N<<2];
const int inf=1e9;
void write(mat &a){
rep(i,0,1){
rep(j,0,1) cout<<a.num[i][j]<<' ';
cout<<endl;
}
}
mat operator * (mat a,mat b){
mat c; rep(i,0,1) rep(j,0,1) c.num[i][j]=-inf;
rep(k,0,1) rep(i,0,1) rep(j,0,1) c.num[i][j]=max(c.num[i][j],a.num[i][k]+b.num[k][j]);
return c;
}
void addedge(int a,int b){
edge[nedge].to=b; edge[nedge].nex=hed[a]; hed[a]=nedge++;
}
void dfs_1(int k){
son[k]=0; sz[k]=1;
repedge(i,k){
int v=edge[i].to; if (v==fa[k]) continue;
fa[v]=k; dep[v]=dep[k]+1;
dfs_1(v);
sz[k]+=sz[v]; if ((!son[k])||(sz[v]>sz[son[k]])) son[k]=v;
}
}
void dfs_2(int k,int tp){
top[k]=tp; tin[k]=++tot;
if (son[k]) dfs_2(son[k],tp); else dw[top[k]]=tot;
repedge(i,k){
int v=edge[i].to; if ((v==fa[k])||(v==son[k])) continue;
dfs_2(v,v);
}tout[k]=tot;
}
void dfs_3(int k){
f[k].num[1][0]=w[k];
repedge(i,k){
int v=edge[i].to; if (v==fa[k]) continue;
dfs_3(v);
f[k].num[0][0]+=max(f[v].num[0][0],f[v].num[1][0]);
f[k].num[1][0]+=f[v].num[0][0];
}
g[k]=f[k];
if (son[k]) g[k].num[0][0]-=max(f[son[k]].num[0][0],f[son[k]].num[1][0]),g[k].num[1][0]-=f[son[k]].num[0][0];
g[k].num[0][1]=g[k].num[0][0];
}
#define lc (nod<<1)
#define rc ((nod<<1)|1)
#define mid ((l+r)>>1)
void pushup(int nod){ tr[nod]=tr[lc]*tr[rc]; }
void update(int l,int r,int nod,int x,mat y){
if (l==r){ tr[nod]=y; return; }
if (x<=mid) update(l,mid,lc,x,y); else update(mid+1,r,rc,x,y);
pushup(nod);
}
mat query(int l,int r,int nod,int ll,int rr){
if ((l==ll)&&(r==rr)) return tr[nod];
if (rr<=mid) return query(l,mid,lc,ll,rr); else if (ll>mid) return query(mid+1,r,rc,ll,rr);
else return query(l,mid,lc,ll,mid)*query(mid+1,r,rc,mid+1,rr);
}
void modify(int a,int b){
g[a].num[1][0]=g[a].num[1][0]-w[a]+b; w[a]=b;
update(1,n,1,tin[a],g[a]);
for(int i=top[a]; ; i=top[fa[i]]){
mat t=query(1,n,1,tin[i],dw[i]);
if (i==1){ f[i]=t; break; } int x=fa[i];
g[x].num[0][0]=g[x].num[0][1]=g[x].num[0][0]
-max(f[i].num[0][0],f[i].num[1][0])+max(t.num[0][0],t.num[1][0]);
g[x].num[1][0]=g[x].num[1][0]-f[i].num[0][0]+t.num[0][0];
update(1,n,1,tin[x],g[x]); f[i]=t;
}
}
int main(){
scanf("%d%d",&n,&m); nedge=0; ms(hed,-1,hed);
rep(i,1,n) scanf("%d",&w[i]);
rep(i,1,n-1){
int a,b; scanf("%d%d",&a,&b);
addedge(a,b); addedge(b,a);
}
dfs_1(1); dfs_2(1,1); dfs_3(1);
rep(i,1,n) update(1,n,1,tin[i],g[i]);
rep(i,1,m){
int a,b; scanf("%d%d",&a,&b);
modify(a,b);
printf("%d\n",max(f[1].num[0][0],f[1].num[1][0]));
}
return 0;
}
史上最鬼鬼鬼鬼鬼畜的NOIP2018day2T3:
#include<bits/stdc++.h>
using namespace std;
#define rep(x,y,z) for (int x=y; x<=z; x++)
#define downrep(x,y,z) for (int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define LL long long
#define repedge(x,y) for (int x=hed[y]; ~x; x=edge[x].nex)
inline int read(){
int x=0; int w=0; char ch=0;
while (ch<'0' || ch>'9') w|=ch=='-',ch=getchar();
while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return w? -x:x;
}
const LL inf=1e10;
const int N=300005;
int n,m,nedge,sz[N],son[N],hed[N],fa[N],dep[N],tin[N],tout[N],dw[N],top[N],tot;
LL p[N];
struct Edge{ int to,nex; }edge[N<<1];
struct mat{
LL num[2][2];
void init(){ ms(num,0,num); }
void one(){ init(); rep(i,0,1) num[i][i]=1; }
}f[N],g[N],tr[N<<2];
mat operator * (mat a,mat b){
mat c; rep(i,0,1) rep(j,0,1) c.num[i][j]=inf;
rep(k,0,1) rep(i,0,1) rep(j,0,1) c.num[i][j]=min(c.num[i][j],a.num[i][k]+b.num[k][j]);
return c;
}
void addedge(int a,int b){
edge[nedge].to=b; edge[nedge].nex=hed[a]; hed[a]=nedge++;
}
void dfs_1(int k){
sz[k]=1; son[k]=0;
repedge(i,k){
int v=edge[i].to; if (v==fa[k]) continue;
fa[v]=k; dep[v]=dep[k]+1; dfs_1(v);
sz[k]+=sz[v]; if ((!son[k])||(sz[v]>sz[son[k]])) son[k]=v;
}
}
void dfs_2(int k,int tp){
top[k]=tp; tin[k]=++tot;
if (son[k]) dfs_2(son[k],tp); else dw[top[k]]=tot;
repedge(i,k){
int v=edge[i].to; if ((v==fa[k])||(v==son[k])) continue;
dfs_2(v,v);
}tout[k]=tot;
}
void dfs_3(int k){
g[k].num[0][0]=p[k]; g[k].num[1][0]=0;
f[k].num[0][0]=p[k]; f[k].num[1][0]=0;
repedge(i,k){
int v=edge[i].to; if (v==fa[k]) continue;
dfs_3(v);
f[k].num[0][0]+=min(f[v].num[0][0],f[v].num[1][0]);
f[k].num[1][0]+=f[v].num[0][0];
if (v==son[k]) continue;
g[k].num[0][0]+=min(f[v].num[0][0],f[v].num[1][0]);
g[k].num[1][0]+=f[v].num[0][0];
}
g[k].num[0][1]=g[k].num[0][0]; g[k].num[1][1]=inf;
}
#define lc (nod<<1)
#define rc ((nod<<1)|1)
#define mid ((l+r)>>1)
void pushup(int nod){ tr[nod]=tr[lc]*tr[rc]; }
void update(int l,int r,int nod,int x,mat y){
if (l==r){ tr[nod]=y; return; }
if (x<=mid) update(l,mid,lc,x,y); else update(mid+1,r,rc,x,y);
pushup(nod);
}
mat query(int l,int r,int nod,int ll,int rr){
if ((l==ll)&&(r==rr)) return tr[nod];
if (rr<=mid) return query(l,mid,lc,ll,rr); else if (ll>mid) return query(mid+1,r,rc,ll,rr);
else return query(l,mid,lc,ll,mid)*query(mid+1,r,rc,mid+1,rr);
}
void modify(int a,LL b){
g[a].num[0][0]+=b-p[a]; p[a]=b; g[a].num[0][1]=g[a].num[0][0];
for(int i=a; i; i=fa[top[i]]){
mat t1=query(1,n,1,tin[top[i]],dw[top[i]]);
update(1,n,1,tin[i],g[i]);
mat t2=query(1,n,1,tin[top[i]],dw[top[i]]);
int x=fa[top[i]];
g[x].num[0][0]+=min(t2.num[0][0],t2.num[1][0])-min(t1.num[0][0],t1.num[1][0]);
g[x].num[0][1]=g[x].num[0][0];
g[x].num[1][0]+=t2.num[0][0]-t1.num[0][0];
}
}
LL pd[2]={inf,-inf};
char type[15];
int main(){
scanf("%d%d%s",&n,&m,&type);
rep(i,1,n) scanf("%lld",&p[i]);
nedge=0; ms(hed,-1,hed);
rep(i,1,n-1){
int a,b; scanf("%d%d",&a,&b);
addedge(a,b); addedge(b,a);
}
dfs_1(1); dfs_2(1,1); dfs_3(1);
rep(i,1,n) update(1,n,1,tin[i],g[i]);
rep(i,1,m){
int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d);
if (((a==fa[c])||(c==fa[a]))&&((!b)&&(!d))){
printf("-1\n"); continue; }
LL tmp1=p[a]; LL tmp2=p[c];
modify(a,pd[b]); modify(c,pd[d]);
mat t=query(1,n,1,tin[1],dw[1]);
LL ans=min(t.num[0][0],t.num[1][0]);
if (b==1) ans=ans-pd[b]+tmp1;
if (d==1) ans=ans-pd[d]+tmp2;
printf("%lld\n",ans);
modify(a,tmp1); modify(c,tmp2);
}
return 0;
}