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\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;
}
Uoj 441 保卫王国的更多相关文章
- noip2018 d2t3 保卫王国 解题报告
保卫王国 电脑卡懒得把题面挪过来了. 朴素 \[ dp_{i,0}=\sum dp_{s,1}\\ dp_{i,1}=\sum \min(dp_{s,0},dp_{s,1})+p_i \] 然后直接动 ...
- LG5024 保卫王国
题意 题目描述 Z 国有\(n\)座城市,\(n - 1\)条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达. Z 国的国防部长小 Z 要在城市中驻扎军队.驻扎军队需要 ...
- 「NOIP2018」保卫王国
「NOIP2018保卫王国」 题目描述 有一棵 \(n\) 个点, 点有点权 \(a_i\),\(m\) 组询问, 每次求钦点两个节点必须选或者必须不选后的树上最小点覆盖. \(1 \leq n, m ...
- 竞赛题解 - NOIP2018 保卫王国
\(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...
- [NOIP2018TG]保卫王国
[NOIP2018TG]保卫王国 BZOJ luogu 当动态dp模板题写的,(全集-最大点权独立集)不能放军队的+inf,必须放军队-inf即可 注意矩阵乘法的顺序问题 #define ll lon ...
- 『保卫王国 树上倍增dp』
保卫王国 Description Z 国有n座城市,n - 1条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达. Z 国的国防部长小 Z 要在城市中驻扎军队.驻扎军队需 ...
- 【比赛】NOIP2018 保卫王国
DDP模板题 #include<bits/stdc++.h> #define ui unsigned int #define ll long long #define db double ...
- luogu5024 [NOIp2018]保卫王国 (动态dp)
可以直接套动态dp,但因为它询问之间相互独立,所以可以直接倍增记x转移到fa[x]的矩阵 #include<bits/stdc++.h> #define CLR(a,x) memset(a ...
- NOIP2018保卫王国
题目大意:给一颗有点权的树,每次规定两个点选还是不选,求这棵树的最小权点覆盖. 题解 ZZ码农题. 要用动态dp做,这题就是板子,然鹅并不会,留坑代填. 因为没有修改,所以可以静态倍增. 我们先做一遍 ...
随机推荐
- [笔记整理]SQL Server 索引碎片 和 重建索引
铺垫知识点: 数据库存储本身是无序的,建立了聚集索引,会按照聚集索引物理顺序存入硬盘.既键值的逻辑顺序决定了表中相应行的物理顺序 多数情况下,数据库读取频率远高于写入频率,索引的存在 为了读取速度牺牲 ...
- 分析java进程假死状况
摘自: http://www.myexception.cn/internet/2044496.html 分析java进程假死情况 1 引言 1.1 编写目的 为了方便大家以后发现进程假死的时候能够正常 ...
- CSS元素隐藏的11种方法
{ display: none; /* 不占据空间,无法点击 */ } { visibility: hidden; /* 占据空间,无法点击 */ } { position: absolute; cl ...
- Memory Manager surface area changes in SQL Server 2012
here were various changes to memory related DMVs, DBCC memory status, and Perfmon counters in SQL Se ...
- JS怎么计算html标签里文字的宽度
方法: 做一个空的html 标签 id为“ruler”,样式为“position:absolute;visibility: hidden; white-space: nowrap;z-index: - ...
- 新东方雅思词汇---9.1、sist
新东方雅思词汇---9.1.sist 一.总结 一句话总结: 站 resist 英 [rɪ'zɪst] 美 [rɪ'zɪst] vi. 抵抗,抗拒:忍耐 vt. 抵抗:忍耐,忍住 n. [助剂] ...
- DataTemplate——数据模板的一个典型例子
下面是ListBox.ItemTemplate(数据模板)应用的“典型”例子,概述如下两点: 1:Grid部分,用来“规划” 数据 显示的 布局(即数据长成什么样子) 2:给DataTempl ...
- angular directive restrict 的用法
E 表示该指令是一个element; A 表示该指令是attribute; C 表示该指令是class; M 表示该指令是注视 实例如下: 原帖:www.thinkster.io/angularjs/ ...
- spoj-ANARC05H -dp
ANARC05H - Chop Ahoy! Revisited! #dynamic-programming Given a non-empty string composed of digits on ...
- 为红米Note 5 Pro编译Lineage OS 15.1的各种坑
安装了ubuntu虚拟机,直接上网repo sync,网速特别慢,中间断了好多次,记得是3天吧,总算是下载成功了.中途还在淘宝上买过付费的VPN代理软件,有时候会打开代理来尝试,也是不太稳定.好歹第1 ...