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​\) .仍然满足结合律..(这东西还有其他用法,可以点进去看看)

1516579-20190303164911662-821234613.png

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

参考

#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);elseupdate(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\n",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;
}

转载于:https://www.cnblogs.com/jklover/p/10466278.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463296.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

行存和列存的区别

写入&#xff1a; 行存储的写入是一次完成&#xff0c;数据的完整性因此可以确定。 列存储需要把一行记录拆分成单列保存&#xff0c;写入次数明显比行存储多。 行存储在写入上占有很大的优势 数据修改&#xff1a; 行存储是在指定位置写入一次&#xff0c;列存储是将磁盘定位…

javascript中的命名规则和方法

javascript变量名需要遵守两条简单的规则&#xff1a;1、第一个字符必须是字母、下划线&#xff08;_&#xff09; 或美圆符号&#xff08;$&#xff09;。2、余下的字符可以是下划线、美圆符号或任何字母或数字字符。 命名方法&#xff1a;1、Camel标记法——首字母是小写的&a…

jquery插件开发导读

最近发现项目中有些js代码可以重用&#xff0c;但是不知道怎么样组织&#xff0c;在网上调研后&#xff0c;发现jquery插件是一种很好的组织方式&#xff0c;而且项目也采用了jquery框架&#xff0c;所以花了点时间学习jquery插件开发&#xff0c;并且动手将部分项目代码转成jq…

C语言缓冲文件系统和非缓冲文件系统

C 语言所使用的磁盘文件系统有两大类&#xff1a;一类称为缓冲文件系统&#xff0c;又称为标准文件系统&#xff1b;另一类称为非缓冲文件系统。缓冲文件系统的特点是系统自动地在内存区为每一个正在使用的文件开辟一个缓冲区。从磁盘向内存读入数据时&#xff0c;则一次从磁盘…

Swift 里集合类型协议的关系

&#xfffc; &#xfffc; Sequence A type that provides sequential, iterated access to its elements. 是最基础的协议&#xff0c;可以通过迭代来获取它的元素。 有两个关联类型&#xff1a; /// A type representing the sequences elements.associatedtype Element//…

ASP.NET 实现登录界面(生成验证码)

这周末也没干啥&#xff0c;真正开始ASP&#xff0c;做了个学籍管理系统的登录界面&#xff0c;登录界面主要包括用户名、密码、验证码&#xff0c;界面字体用了<font size"5" color"blue" font-family:"华文琥珀";></font>改变字体…

C/C++语言void及void指针深层探索

1.概述  许多初学者对C/C语言中的void及void指针类型不甚理解&#xff0c;因此在使用上出现了一些错误。本文将对void关键字的深刻含义进行解说&#xff0c;并详述void及void指针类型的使用方法与技巧。2.void的含义  void的字面意思是“无类型”&#xff0c;void *则为“无…

多域资源整合之基础准备--DNS配置

由于公司的战略调整,需要整合集团内的资源,当然也也包含IT资源,我们需要评估多家公司的IT架构统一,顺利的合并到总集团的IT架构里,这也就产生一个多域的整合的一个案例,在此分享给大家,希望对大家有所帮助&#xff01;篇幅较长&#xff0c;让我们慢慢细化&#xff01; 在这次的…

python__实参前加*和**的(拆包)功能

print(--------元组打散--------) tup(1,2,3) print(tup) print(*tup) print(--------列表打散--------) list[1,2,3] print(list) print(*list) print(--------字符串打散------) strhello print(str) print(*str) print(--------字典打散--------) def func_dic(name,age):pr…

内存淘汰机制 LRU cache

LRU cache机制的目的是为了减少频繁查找的开销&#xff0c;包括磁盘IO等。 (1)、如果LRU中存在则从LRU缓存中查找&#xff0c;查找到了之后放到容器(list)的最前面 (2)、如果缓存中没有&#xff0c;则从其地方(数据库、磁盘、文件)中读取&#xff0c;读取之后放到容器的最前面…

字符与字符串操作——Windows via C/C++

在最新版的Windows, Windows Vista&#xff0c;它应该支持Unicode 5.0。在编程中对字符与字符串的操作是很普通的&#xff0c;为新的系统写代码&#xff0c;尽可能使用Unicode&#xff0c;它提供了更好的性能&#xff0c;以及可以进行区域化。而且与COM及.Net框架互操作时也有帮…

cmd常用命令总结

CMD命令&#xff1a;开始&#xff0d;>运行&#xff0d;>键入cmd或command&#xff08;在命令行里可以看到系统版本、文件系统版本&#xff09;chcp 修改默认字符集chcp 936默认中文chcp 650011. appwiz.cpl&#xff1a;程序和功能 2. calc&#xff1a;启动计算器 5. ch…

生产者-消费者模式的实现

// 生产者-消费者模式 无锁队列 get()时&#xff0c;如果deque里面没有元素了&#xff0c;则会一直阻塞,还有待改进的空间 template <class T> class BlockingQueue { public:explicit BlockingQueue() : shutdown_(false) {}~BlockingQueue() {}void put(const T&a…

《面向模式的软件体系结构2-用于并发和网络化对象模式》读书笔记(13)--- 线程安全接口和双检查加锁优化...

4.3线程安全接口&#xff08;Thread-Safe Interface&#xff09;1.问题多线程组件通常包括多个可被公共访问的接口方法以及可以改变组件状态的私有方法。为了避免出现竞争条件&#xff0c;可以使用一个组件内部的锁对访问其状态的接口方法调用串行化。尽管当每个方法都自包容的…

C++流的基本概念

在C语言中&#xff0c;数据的输入和输出&#xff08;简写为I/O&#xff09;包括对标准输入设备键盘和标准输出设备显示器、对在外存磁盘上的文件和对内存中指定的字符串存储空间&#xff08;当然可用该空间存储任何信息&#xff09;进行输入输出这三个方面。对标准输入设备和标…

天哪,flash cs4可以使动态文本旋转了

天哪&#xff0c;flash cs4可以使动态文本旋转了. 只要使用rotationZ属性即可。 这可是解决了一个跨世纪的问题&#xff0c;爽爽爽。 啊哈哈哈。 这是测试源代码。 var rTextField:TextFieldnewTextField();var textFormat:TextFormatnewTextFormat();rTextField.text"…

Java编译过程(传送门)

我不是要做一门编程语言&#xff0c;了解这个对我现在的工作也没什么帮助&#xff0c;纯粹好奇而已。 传送门转载于:https://www.cnblogs.com/flying607/p/10481239.html

Linux 系统如何调整时区和时间

比如我要吧机器调成太平洋时区&#xff0c;那么我可以输入以下的命令&#xff0c;我们创建一个Link文件来指明是Pacific Time&#xff1a; cd /etc/ rm –r localtime sudo ln -s /usr/share/zoneinfo/US/Pacific localtime 调节完时区之后&#xff0c;接下来就是设置时间&a…

C语言typedefine 和define的区别

define &#xff1a; 宏定义&#xff0c;在预编译阶段就进行处理&#xff0c;简单的字符串代换&#xff0c;typedefine&#xff1a; 编译时进行处理&#xff0c;不是简单的替换&#xff0c;而是对类型说明符的重新命名。被命名的标识符具有类型说明的功能&#xff0c;代码说明#…

博客园“图灵杯”第3届博问大赛比赛结果

经过近一个月的激烈角逐&#xff0c;博客园“图灵杯”第三届博问大赛已圆满结束。获奖园友分别是&#xff1a; 一等奖&#xff1a;邀月&#xff08;奖励图灵图书4本&#xff09; 二等奖&#xff1a;Kinglee、邢少&#xff08;奖励图灵图书2本&#xff09; 三等奖&#xff1a;Gr…