• 洛谷5024 保卫王国 (动态dp)


    qwq非正解。
    但是能跑过。
    1e5 log方还是很稳的啊

    首先,考虑最普通的(dp)
    (dp1[x][0]表示不选这个点,dp1[x][1]表示选这个点的最大最小花费)
    那么
    (dp1[x][0]=sum dp[p][1])
    (dp1[x][1]=sum min(dp[p][1],dp[p][0])+val[x])

    根据套路,我们要树链剖分+改变(dp)数组,我们令(f[x])表示忽略重儿子的(dp)值,用(g)表示正常的(dp)值的话

    那么不难发现转移矩阵应该是

    {g[p][0],g[p][1]} 
    

    乘上

    inf f[x][1]
    f[x][0] f[x][1]
    

    等于

    g[x][0] g[x][1]
    

    qwq
    然后其他的就是动态dp的部分了

    但是需要注意的一个地方是。
    你如果通过写一个类似的(modify)

    void modify(int x,Ju y)
    {
    	update(1,1,n,newnum[x],y);
    	for (int now=top[x];now!=1;now=top[now])
    	{
    		int faa = fa[now];
    		Ju ymh = query(1,1,n,newnum[faa],newnum[faa]);
    		Ju lyf = query(1,1,n,newnum[now],newnum[tail[top[now]]]);
    		ymh.a[1][2]+=min(lyf.a[1][2],lyf.a[1][1]) - min(pre[now].a[1][2],pre[now].a[1][1]);
    		ymh.a[2][2]=ymh.a[1][2];
    		ymh.a[2][1]+=lyf.a[1][2]-pre[now].a[1][2];
    		if (faa==tail[top[faa]]) ymh.a[1][1]=ymh.a[2][1];
    		update(1,1,n,newnum[faa],ymh);
    		pre[now]=lyf;
    		now = fa[now];
    	}
    }
    

    你需要(modify)三次,才可以。因为你第一次(modify)实际上是基于另一个不还原的前提下来还原第一个,但是实际上,我们是要求在另一个还原过的基础上还原第一个。

    但是如果你用如下的函数进行还原的话

    void wei(int x)
    {
    	update(1,1,n,newnum[x],ymh[x]);
    	for (int now = top[x];now!=1;now=top[now])
    	{
    		int faa = fa[now];
    		update(1,1,n,newnum[faa],ymh[faa]);
    		pre[now]=bre[now];
    		now=fa[now];
    	}
    }
    

    直接给代码

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<set>
    #define pb push_back
    #define mk make_pair
    #define ll long long
    #define lson ch[x][0]
    #define rson ch[x][1]
    
    using namespace std;
    
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    
    const int maxn = 2e5+1e2;
    const int maxm = 2*maxn;
    const ll inf = 1e18;
    
    struct Ju{
    	int x,y;
    	ll a[3][3];
    	Ju operator * (Ju b)
    	{
    		Ju ans;
    		ans.x=2;
    		ans.y=2;
    		memset(ans.a,127/3,sizeof(ans.a));
    		for (int i=1;i<=2;i++)
    		{
    			for (int j=1;j<=2;j++)
    			  for (int k=1;k<=2;k++)
    			  {
    			  	 ans.a[i][j]=min(ans.a[i][j],a[i][k]+b.a[k][j]);
    			  }
    		}
    		return ans;
    	}
    };
    
    Ju f[4*maxn];
    Ju pre[maxn];
    int point[maxn],nxt[maxm],to[maxm];
    int cnt,n,m,q;
    ll val[maxn],dp1[maxn][2],dp[maxn][2];
    Ju ymh[maxn];
    int fa[maxn],size[maxn],son[maxn],back[maxn],newnum[maxn];
    int tail[maxn],top[maxn];
    
    void addedge(int x,int y)
    {
    	nxt[++cnt]=point[x];
    	to[cnt]=y;
    	point[x]=cnt;
    }
    
    void up(int root)
    {
    	f[root]=f[2*root+1]*f[2*root]; 
    }
    
    Ju bre[maxn];
    
    void build(int root,int l,int r)
    {
    	if (l==r)
    	{
    		int now = back[l];
    		f[root].x=f[root].y=2;
    		if (tail[top[now]]==now)
    		{
    			f[root].a[1][1]=dp[now][0];
    			f[root].a[1][2]=dp[now][1];
    			f[root].a[2][1]=f[root].a[1][1];
    			f[root].a[2][2]=f[root].a[1][2];
    		}
    		else
    		{
    		  f[root].a[1][1]=inf;
    		  f[root].a[1][2]=dp[now][1];
    		  f[root].a[2][1]=dp[now][0];
    		  f[root].a[2][2]=dp[now][1];
    	    }
    	    ymh[now]=f[root];
    	    return;
    	}
    	int mid = l+r >> 1;
        build(2*root,l,mid);
    	build(2*root+1,mid+1,r);
    	up(root); 
    }
    
    void update(int root,int l,int r,int x,Ju p)
    {
    	if(l==r) 
    	{
    		f[root]=p;
    		return;
    	}
    	int mid = l+r >> 1;
    	if (x<=mid) update(2*root,l,mid,x,p);
    	else update(2*root+1,mid+1,r,x,p);
    	up(root);
    }
    
    Ju query(int root,int l,int r,int x,int y)
    {
    	if (x<=l && r<=y) return f[root];
    	int mid = l+r>>1;
        if (y<=mid) return query(2*root,l,mid,x,y);
        if (x>mid) return query(2*root+1,mid+1,r,x,y);
        return query(2*root+1,mid+1,r,x,y)*query(2*root,l,mid,x,y);
    }
    
    
    void dfs1(int x,int faa)
    {
    	size[x]=1;
    	int maxson=-1;
    	for (int i=point[x];i;i=nxt[i])
    	{
    		int p = to[i];
    		if (p==faa) continue;
    		fa[p]=x;
    		dfs1(p,x);
    		size[x]+=size[p];
    		if (size[p]>maxson)
    		{
    			maxson=size[p];
    			son[x]=p;
    		}
    	}
    } 
    
    int tot;
    
    void dfs2(int x,int chain)
    {
    	top[x]=chain;
    	tail[chain]=x;
    	newnum[x]=++tot;
    	back[tot]=x;
    	if (!son[x]) return;
    	dfs2(son[x],chain);
    	for (int i=point[x];i;i=nxt[i])
    	{
    		int p = to[i];
    		if (!newnum[p]) dfs2(p,p);
    	}
    }
    
    void solve(int x,int fa)
    {
    	dp1[x][1]=dp[x][1]=val[x];
    	for (int i=point[x];i;i=nxt[i])
    	{
    		int p = to[i];
    		if (p==fa) continue;
    		solve(p,x); 
    		dp1[x][0]=dp1[x][0]+dp1[p][1];
    		dp1[x][1]=dp1[x][1]+min(dp1[p][0],dp1[p][1]);
    		if (p!=son[x])
    		{
    			dp[x][0]=dp[x][0]+dp1[p][1];
    			dp[x][1]=dp[x][1]+min(dp1[p][0],dp1[p][1]);
    		}
    	}
    }
    
    int uu;
    
    void modify(int x,Ju y)
    {
    	update(1,1,n,newnum[x],y);
    	for (int now=top[x];now!=1;now=top[now])
    	{
    		int faa = fa[now];
    		Ju ymh = query(1,1,n,newnum[faa],newnum[faa]);
    		Ju lyf = query(1,1,n,newnum[now],newnum[tail[top[now]]]);
    		ymh.a[1][2]+=min(lyf.a[1][2],lyf.a[1][1]) - min(pre[now].a[1][2],pre[now].a[1][1]);
    		ymh.a[2][2]=ymh.a[1][2];
    		ymh.a[2][1]+=lyf.a[1][2]-pre[now].a[1][2];
    		if (faa==tail[top[faa]]) ymh.a[1][1]=ymh.a[2][1];
    		update(1,1,n,newnum[faa],ymh);
    		pre[now]=lyf;
    		now = fa[now];
    	}
    }
    
    void wei(int x)
    {
    	update(1,1,n,newnum[x],ymh[x]);
    	for (int now = top[x];now!=1;now=top[now])
    	{
    		int faa = fa[now];
    		update(1,1,n,newnum[faa],ymh[faa]);
    		pre[now]=bre[now];
    		now=fa[now];
    	}
    }
    signed main()
    {
      n=read();m=read(),uu=read(); 
      for (int i=1;i<=n;i++) val[i]=read();
      for (int i=1;i<n;i++)
      {
      	int x=read(),y=read();
      	addedge(x,y);
      	addedge(y,x);
      }
      dfs1(1,0);
      dfs2(1,1);
      solve(1,0);
      build(1,1,n);
      for (int i=1;i<=n;i++)
      {
      	 pre[i]=query(1,1,n,newnum[i],newnum[tail[top[i]]]);
      	// cout<<i<<" "<<pre[i].a[1][1]<<" "<<pre[i].a[1][2]<<endl;
      	bre[i]=pre[i];
      }
      for (int i=1;i<=m;i++)
      {
      	int a=read(),x=read(),b=read(),y=read();
      	Ju tmp = query(1,1,n,newnum[a],newnum[a]);
      	if (x==0)
    	{
    	  if (a!=tail[top[a]])
    	  {
    	    tmp.a[1][2]=inf;
    	    tmp.a[2][2]=inf; 
    	  }
    	  else
    	  {
    	  	 tmp.a[1][2]=inf;
    	  	 tmp.a[2][2]=inf;
    	  }
    	} 
    	else
    	{
    		if (a!=tail[top[a]])
    		tmp.a[2][1]=inf;
    		else tmp.a[1][1]=tmp.a[2][1]=inf;
    	}
    	modify(a,tmp);
    	tmp = query(1,1,n,newnum[b],newnum[b]);
    	if (y==0)
    	{
    		tmp.a[1][2]=tmp.a[2][2]=inf;
    	}
    	else
    	{
    		if (b!=tail[top[b]])
    		tmp.a[2][1]=inf;
    		else tmp.a[1][1]=tmp.a[2][1]=inf;
    	}
    	modify(b,tmp);
        Ju now = query(1,1,n,newnum[1],newnum[tail[top[1]]]);
        ll ptx = min(now.a[1][1],now.a[1][2]);
        if (ptx>=inf) ptx=-1;
        cout<<ptx<<"
    ";
        modify(a,ymh[a]);
        modify(b,ymh[b]);
        //wei(a);
        //wei(b);
        modify(a,ymh[a]);
      } 
      return 0;
    }
    
    
  • 相关阅读:
    三步搭建精准召回体系,挽回流失用户
    HMS Core Insights第二期直播预告——华为定位技术让你重拾方向感
    如何区分router.push跳转快应用的来源渠道
    华为预测服务的构建原理是什么?该如何训练模型?
    HarmonyOS开发者日干货资料,奉上!
    技术硬核、体验新颖……HarmonyOS开发者日最值得关注的点都在这里
    Js中Proxy对象
    迭代器模式
    ed命令
    百度实习生前端面试面经
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10297204.html
Copyright © 2020-2023  润新知