luogu4719+NOIP2018day2T3 动态dp

在进入正文以前,我想先哭一下。

嘤嘤嘤嘤嘤嘤嘤

嘤嘤嘤嘤嘤嘤嘤

嘤嘤嘤我嘤嘤嘤

嘤嘤嘤嘤嘤嘤嘤

嘤嘤嘤嘤嘤嘤嘤

事实上在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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值