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 保卫王国的更多相关文章

  1. noip2018 d2t3 保卫王国 解题报告

    保卫王国 电脑卡懒得把题面挪过来了. 朴素 \[ dp_{i,0}=\sum dp_{s,1}\\ dp_{i,1}=\sum \min(dp_{s,0},dp_{s,1})+p_i \] 然后直接动 ...

  2. LG5024 保卫王国

    题意 题目描述 Z 国有\(n\)座城市,\(n - 1\)条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达. Z 国的国防部长小 Z 要在城市中驻扎军队.驻扎军队需要 ...

  3. 「NOIP2018」保卫王国

    「NOIP2018保卫王国」 题目描述 有一棵 \(n\) 个点, 点有点权 \(a_i\),\(m\) 组询问, 每次求钦点两个节点必须选或者必须不选后的树上最小点覆盖. \(1 \leq n, m ...

  4. 竞赛题解 - NOIP2018 保卫王国

    \(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...

  5. [NOIP2018TG]保卫王国

    [NOIP2018TG]保卫王国 BZOJ luogu 当动态dp模板题写的,(全集-最大点权独立集)不能放军队的+inf,必须放军队-inf即可 注意矩阵乘法的顺序问题 #define ll lon ...

  6. 『保卫王国 树上倍增dp』

    保卫王国 Description Z 国有n座城市,n - 1条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达. Z 国的国防部长小 Z 要在城市中驻扎军队.驻扎军队需 ...

  7. 【比赛】NOIP2018 保卫王国

    DDP模板题 #include<bits/stdc++.h> #define ui unsigned int #define ll long long #define db double ...

  8. luogu5024 [NOIp2018]保卫王国 (动态dp)

    可以直接套动态dp,但因为它询问之间相互独立,所以可以直接倍增记x转移到fa[x]的矩阵 #include<bits/stdc++.h> #define CLR(a,x) memset(a ...

  9. NOIP2018保卫王国

    题目大意:给一颗有点权的树,每次规定两个点选还是不选,求这棵树的最小权点覆盖. 题解 ZZ码农题. 要用动态dp做,这题就是板子,然鹅并不会,留坑代填. 因为没有修改,所以可以静态倍增. 我们先做一遍 ...

随机推荐

  1. Restore IP Addresses,将字符串转换成ip地址

    问题描述: Given a string containing only digits, restore it by returning all possible valid IP address c ...

  2. java_zlib_资料

    1.网页资料 1.1.http://bbs.csdn.net/topics/190020986 1.2. http://cdn.verydemo.com/demo_c89_i166794.html h ...

  3. SSH密钥登陆免密码方法

    原帖地址:http://ask.apelearn.com/question/798 用Putty实现A机器远程登陆B机器,具体实现请看链接:http://www.cnblogs.com/ImJerry ...

  4. 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 ...

  5. Angular2-使用Augury来调试Angular2程序

    参考: http://www.jianshu.com/p/efecaea287f2https://augury.angular.io/ https://augury.angular.io/pages/ ...

  6. spring mvc:视图解析器

    ModelAndView对象中的view对象,可以使用字符串来让Spring框架进行解析获得适合的视图.而解析View的就是ViewResolver技术. ViewResolver的定义如下: pub ...

  7. Highcharts 测量图;Highcharts 圆形进度条式测量图;Highcharts 时钟;Highcharts 双轴车速表;Highcharts 音量表(VU Meter)

    Highcharts 测量图 配置 chart.type 配置 配置 chart 的 type 为 'gauge' .chart.type 描述了图表类型.默认值为 "line". ...

  8. Linux 磁盘管理,Linux vi/vim

    一.Linux 磁盘管理 Linux磁盘管理好坏直接关系到整个系统的性能问题. Linux磁盘管理常用三个命令为df.du和fdisk. df:列出文件系统的整体磁盘使用量 du:检查磁盘空间使用量 ...

  9. hdu 5802 Windows 10 (dfs)

    Windows 10 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  10. Map以及其子类

    package com.Map; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; i ...