zoukankan      html  css  js  c++  java
  • Uoj 441 保卫王国

    Uoj 441 保卫王国

    • 动态 (dp) .今天才来写这个题.
    • (f[u][0/1]) 表示子树 (u) 中不选/选 (u) 时的最小权值和,显然有:(f[u][0]=sum f[v][1] ,f[u][1]=w[u]+sum min(f[v][0],f[v][1])​) .
    • 现在要资瓷修改 (x) 的点权 (w[x]) ,容易发现修改后只会影响 (x) 到根节点这一条链上的 (f) 值.若暴力更新这一条链,在树深度大时,时间复杂度仍是 (O(nm)) 的.考虑使用树剖来维护,尝试快速更新信息.
    • 由于树剖后,一个节点到根节点的路径上,轻边/重链都不会超过 (logn) 条,可以暴力修改轻儿子的贡献,用数据结构来维护重链.那么轻重儿子的信息需要分开存,用 (g[u][0/1]) 表示子树 (u) 除去重儿子的子树后, 不选/选 (u) 时的最小权值和.
    • 转移可以用下面这个转移矩阵表示,这里是 Min-plus matrix multiplication ,即将原来矩阵乘法的乘法换成加法,加法换成取 (min​) .仍然满足结合律..(这东西还有其他用法,可以点进去看看)

    • 用线段树维护区间矩阵乘积即可.

    参考

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
    	ll out=0,fh=1;
    	char jp=getchar();
    	while ((jp>'9'||jp<'0')&&jp!='-')
    		jp=getchar();
    	if (jp=='-')
    		fh=-1,jp=getchar();
    	while (jp>='0'&&jp<='9')
    		out=out*10+jp-'0',jp=getchar();
    	return out*fh;
    }
    const int MAXN=1e5+10;
    int n,m;
    int nx[MAXN<<1],to[MAXN<<1],head[MAXN],cnt=0;
    inline void addedge(int u,int v)
    {
    	++cnt;
    	nx[cnt]=head[u];
    	to[cnt]=v;
    	head[u]=cnt;
    	swap(u,v);
    	++cnt;
    	nx[cnt]=head[u];
    	to[cnt]=v;
    	head[u]=cnt;
    }
    ll w[MAXN];
    ll f[MAXN][2],g[MAXN][2];
    int fa[MAXN],mxson[MAXN],siz[MAXN],dep[MAXN],dfn[MAXN],rnk[MAXN],top[MAXN],bot[MAXN],idx=0;
    void DP(int u,int Fa)
    {
    	f[u][1]=w[u];
    	for(int i=head[u];i;i=nx[i])
    		{
    			int v=to[i];
    			if(v==Fa)
    				continue;
    			DP(v,u);
    			f[u][0]+=f[v][1];
    			f[u][1]+=min(f[v][0],f[v][1]);
    		}
    }
    void dfs1(int u,int Fa)
    {
    	fa[u]=Fa;
    	siz[u]=1;
    	dep[u]=dep[Fa]+1;
    	for(int i=head[u];i;i=nx[i])
    		{
    			int v=to[i];
    			if(v==Fa)
    				continue;
    			dfs1(v,u);
    			siz[u]+=siz[v];
    			if(siz[v]>siz[mxson[u]])
    				mxson[u]=v;
    		}
    }
    void dfs2(int u,int tp)
    {
    	top[u]=tp;
    	dfn[u]=++idx;
    	rnk[idx]=u;
    	if(mxson[u])
    		dfs2(mxson[u],tp);
    	for(int i=head[u];i;i=nx[i])
    		{
    			int v=to[i];
    			if(v!=fa[u] && v!=mxson[u])
    				dfs2(v,v);
    		}
    }
    const ll inf=1e18;
    struct node{
    	ll v[2][2];
    	int l,r;
    	node(){v[0][0]=v[0][1]=v[1][0]=v[1][1]=inf;}
    	node operator * (const node &rhs) const
    		{
    			node res;
    			res.l=l,res.r=rhs.r;
    			for(int k=0;k<2;++k)
    				for(int i=0;i<2;++i)
    					for(int j=0;j<2;++j)
    						res.v[i][j]=min(res.v[i][j],v[i][k]+rhs.v[k][j]);
    			return res;
    		}
    };
    node val[MAXN];
    struct SegTree{	
    	node Tree[MAXN<<2];
    	#define root Tree[o]
    	#define lson Tree[o<<1]
    	#define rson Tree[o<<1|1]
    	inline void pushup(int o)
    		{
    			root=lson*rson;
    		}
    	void BuildTree(int o,int l,int r)
    		{
    			root.l=l,root.r=r;
    			if(l==r)
    				{
    					int u=rnk[l],g[2];
    					g[0]=0,g[1]=w[u];
    					for(int i=head[u];i;i=nx[i])
    						{
    							int v=to[i];
    							if(v==fa[u] || v==mxson[u])
    								continue;
    							g[0]+=f[v][1];
    							g[1]+=min(f[v][0],f[v][1]);
    						}
    					root.v[0][0]=inf,root.v[0][1]=g[0];
    					root.v[1][0]=root.v[1][1]=g[1];
    					val[l]=root;
    					return;
    				}
    			int mid=(l+r)>>1;
    			BuildTree(o<<1,l,mid);
    			BuildTree(o<<1|1,mid+1,r);
    			pushup(o);
    		}
    	void update(int o,int pos)
    		{
    			int l=root.l,r=root.r;
    			if(l==r)
    				{
    					root=val[pos];
    					return;
    				}
    			int mid=(l+r)>>1;
    			if(pos<=mid)
    				update(o<<1,pos);
    			else
    				update(o<<1|1,pos);
    			pushup(o);
    		}
    	node query(int o,int L,int R)
    		{
    			int l=root.l,r=root.r;
    			if(L<=l && r<=R)
    				return root;
    			int mid=(l+r)>>1;
    			if(R<=mid)
    				return query(o<<1,L,R);
    			if(L>mid)
    				return query(o<<1|1,L,R);
    			return query(o<<1,L,R)*query(o<<1|1,L,R);
    		}
    }T;
    node query(int x)
    {
    	return T.query(1,dfn[x],dfn[bot[x]]);
    }
    ll getans()
    {
    	node s=query(1);
    	return min(s.v[0][1],s.v[1][1]);
    }
    void upd(int x,ll nv)
    {
    	val[dfn[x]].v[1][0]-=w[x]-nv;
    	val[dfn[x]].v[1][1]-=w[x]-nv;
    	w[x]=nv;
    	while(x)
    		{
    			node org=query(top[x]);
    			T.update(1,dfn[x]);
    			node nx=query(top[x]);
    			x=fa[top[x]];
    			val[dfn[x]].v[0][1]+=nx.v[1][1]-org.v[1][1];
    			val[dfn[x]].v[1][0]+=min(nx.v[1][1],nx.v[0][1])-min(org.v[1][1],org.v[0][1]);
    			val[dfn[x]].v[1][1]=val[dfn[x]].v[1][0];
    		}
    }
    void solve(int x1,int t1,int x2,int t2)
    {
    	if(t1==0 && t2==0 && (fa[x1]==x2 || fa[x2]==x1))
    		return void(puts("-1"));
    	ll v1=w[x1],v2=w[x2];
    	upd(x1,v1+(t1?-inf:inf));
    	upd(x2,v2+(t2?-inf:inf));
    	ll res=getans();
    	res+=t1?inf:0;
    	res+=t2?inf:0;
    	printf("%lld
    ",res);
    	upd(x1,v1);
    	upd(x2,v2);
    }
    char tip[5];
    signed main()
    {
    	//freopen("tx.in","r",stdin);
    	n=read(),m=read();
    	scanf("%s",tip);
    	for(int i=1;i<=n;++i)
    		w[i]=read();
    	for(int i=1;i<n;++i)
    		{
    			int u=read(),v=read();
    			addedge(u,v);
    		}
    	DP(1,0);
    	dfs1(1,0);
    	dfs2(1,1);
    	for(int i=1;i<=n;++i)
    		{
    			if(i==top[i])
    				{
    					int t=i;
    					while(mxson[t])
    						t=mxson[t];
    					bot[i]=t;
    				}
    		}
    	T.BuildTree(1,1,n);
    	while(m--)
    		{
    			int a=read(),b=read(),c=read(),d=read();
    			solve(a,b,c,d);
    		}
    	return 0;
    }
    
  • 相关阅读:
    1、电源管理概念
    37、mipg-streamer的使用讲解
    ARM+linux学习过程(3)mini2440的USB驱动无法在win7下识别
    ARM+linux学习过程(2)安装vmware-tool过程与错误解决
    ARM+linux学习过程(1)虚拟机下ubuntu上网
    35、在编译Linux内核中增加程序需要完成以下3项工作
    36、ALSA声卡驱动和应用
    35、在JZ2440上使用3G上网卡
    POJ
    CF453-A Visiting a Friend (dfs)
  • 原文地址:https://www.cnblogs.com/jklover/p/10466278.html
Copyright © 2011-2022 走看看