[集训队作业2018] 三角形(贪心,堆,线段树合并)

传送门

首先,在结点uuu放上w[u]w[u]w[u]个石子后,出于贪心考虑,下一步一定会把uuu的所有儿子vvv上的石子收回手中。

转换题意:
cntcntcnt为当下树上的石子数,对每个结点uuu可以执行一次操作:

  • step1. cnt+=w[u]cnt+=w[u]cnt+=w[u]
  • step2. cnt−=∑v∈son(u)w[v]cnt-=\sum_{v\in son(u)}w[v]cnt=vson(u)w[v]

当且仅当对uuu的所有儿子vvv都执行过操作,才能对uuu执行操作。
问历史上cntcntcnt的最大值最小可以是多少?

先不考虑 儿子都操作完父亲才能操作的限制,思考一个简单版问题:有nnn个操作(a[i],b[i])(a[i],b[i])(a[i],b[i]),其含义为:先令cnt+=a[i]cnt+=a[i]cnt+=a[i],再令cnt+=b[i]cnt+=b[i]cnt+=b[i]。对这nnn个操作排序,使历史上cntcntcnt的最大值最小。(a[i]=w[i],b[i]=−∑w[v]a[i]=w[i],b[i]=-\sum w[v]a[i]=w[i],b[i]=w[v]

对于一段操作i,i+1,...,ji,i+1,...,ji,i+1,...,j,设经过这段操作后cnt=cnt+deltacnt=cnt+deltacnt=cnt+delta,且执行这段操作途中历史上cntcntcnt的最大值为cnt+mxcnt+mxcnt+mx

那么每次向后添加一个二元组(a[j+1]=w[j+1],b[j+1]=−∑w[v])(a[j+1]=w[j+1],b[j+1]=-\sum w[v])(a[j+1]=w[j+1],b[j+1]=w[v])
就相当于delta←delta+w[j+1]−∑w[v],mx←max(mx,mx+w[j+1])delta\leftarrow delta+w[j+1]-\sum w[v],mx\leftarrow max(mx,mx+w[j+1])deltadelta+w[j+1]w[v],mxmax(mx,mx+w[j+1])

所以我们换一种方式,用二元组(w[i]−∑w[v],w[i])(w[i]-\sum w[v],w[i])(w[i]w[v],w[i])来描述操作iii
(相当于操作段iii(delta,mx)(delta,mx)(delta,mx)

由上面可以发现这个二元组是可以简易复合的。我们的问题就是给这些二元组安排一个优先级,使得从左到右复合之后mxmxmx最小。

可以证明,对于二元组A,BA,BA,B,定义 +++ 为复合操作,AAA的优先级比BBB高当且仅当(A+B).max<(B+A).max(A+B).max<(B+A).max(A+B).max<(B+A).max,且这样保证不存在二元组A,B,CA,B,CA,B,C满足 A<B,B<C,C<AA<B,B<C,C<AA<B,B<C,C<A 。证明需要进行分类讨论:

因为复合顺序改变deltadeltadelta不变,所以只需考虑复合后的mxmxmx,显然mxmxmx 越小越好

  • 对于deltadeltadelta为负的二元组,一定比deltadeltadelta为正的二元组优。
  • 对于deltadeltadelta都为负的二元组,mxmxmx越小的优先级越高。
  • 对于deltadeltadelta都为正的二元组,delta−mxdelta−mxdeltamx越小的优先级越高。

然后我们就证明了不存在二元组A,B,CA,B,CA,B,C满足A<B,B<C,C<AA<B,B<C,C<AA<B,B<C,C<A,即可以按照这个优先级给二元组排序,且这样最小化最终的mxmxmx
这样就解决了简化问题。

考虑原问题。
uuu的所有儿子vvv都执行过操作才能对uuu执行操作 这个限制非常麻烦,考虑反转:
对每个点uuu可以执行一次操作:

  • step1. 把∑v∈son(u)w[v]\sum_{v\in son(u)}w[v]vson(u)w[v]接到序列ccc的最后面
  • step2. 把−w[u]-w[u]w[u]接到序列ccc的最后面

uuu的父亲fff执行过操作才能对uuu执行操作。
问序列ccc后缀和的最大值最小可以是多少。
(反转前相当于每个操作先把w[u]w[u]w[u]接到ccc的最后面,再把−∑w[v]-\sum w[v]w[v]接到ccc的最后面,求最终的ccc序列的前缀和的最大值最小可以是多少)

转化后uuu点的操作对应的二元组为(∑w[v]−w[u],∑w[v])(\sum w[v]-w[u],\sum w[v])(w[v]w[u],w[v])

观察发现,任意两个二元组合并以后优先级至少比之前的一个二元组优先级低,所以对于某一时刻优先级最高的二元组,就算其父亲还没有放,其也会在其父亲被放之后马上被放,所以可以直接将这个二元组与它的父亲合并。那么用一个堆维护一下当前优先级最高的二元组,就得到了根的答案的操作序列。

最后有一个结论,对于任意一个节点,其答案的操作序列一定是根的操作序列的一个子序列,这里不太需要证明,直接从优先级的角度考虑就好了,所以用线段树合并维护每一个子树里的操作序列和结合后的答案即可,总复杂度 O(nlogn)O(nlogn)O(nlogn)

#include<iostream>
#include<cstdio>
#include<vector>
#include<set>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=2e5+10;
int T,n,par[N],fa[N];
int vis[N],b[N],c[N],tim;
int rt[N];
ll w[N],sw[N],ans[N];
vector<int> g[N],vec[N];
struct Node{ll delta,mx;int id;friend Node operator + (Node a,Node b){return (Node){a.delta+b.delta,max(a.mx,a.delta+b.mx),a.id};}friend bool operator < (Node a,Node b){ll tmp1=max(a.mx,a.delta+b.mx);ll tmp2=max(b.mx,b.delta+a.mx);if(tmp1!=tmp2) return tmp1<tmp2;if(a.delta!=b.delta) return a.delta<b.delta;if(a.mx!=b.mx) return a.mx<b.mx;return a.id<b.id;}
}a[N];
set<Node> s;
int find(int x){if(x==fa[x]) return x;return fa[x]=find(fa[x]);
}
void init(int x){vis[x]=1;b[x]=++tim;c[tim]=x;for(int i=0;i<vec[x].size();i++) init(vec[x][i]);
}
namespace Seg{int ls[N*30],rs[N*30],tot;Node tr[N*30];void pushup(int u){if(!ls[u]){tr[u]=tr[rs[u]];return;}if(!rs[u]){tr[u]=tr[ls[u]];return;}tr[u]=tr[ls[u]]+tr[rs[u]];}void insert(int &u,int l,int r,int pos){if(!u) u=++tot;if(l==r){tr[u]=a[l];return;}int mid=(l+r)>>1;if(pos<=mid) insert(ls[u],l,mid,pos);else insert(rs[u],mid+1,r,pos);pushup(u);}int merge(int x,int y){if(!x||!y) return x+y;ls[x]=merge(ls[x],ls[y]);rs[x]=merge(rs[x],rs[y]);pushup(x);return x;}
}
void dfs(int u){Seg::insert(rt[u],1,n,b[u]);for(int i=0;i<g[u].size();i++){int v=g[u][i];dfs(v);rt[u]=Seg::merge(rt[u],rt[v]);}ans[u]=Seg::tr[rt[u]].mx;
}
int main(){scanf("%d",&T);scanf("%d",&n);for(int i=2;i<=n;i++){scanf("%d",&par[i]);g[par[i]].push_back(i);}for(int i=1;i<=n;i++){scanf("%lld",&w[i]);sw[par[i]]+=w[i];fa[i]=i;}for(int i=1;i<=n;i++){a[i]=(Node){sw[i]-w[i],sw[i],i};s.insert(a[i]);}for(int i=1;i<=n;i++){Node now=*(s.begin()); s.erase(s.begin());int x=now.id;if(x==1||vis[par[x]]) init(x);else{int fx=find(par[x]);s.erase(a[fx]);a[fx]=a[fx]+a[x];s.insert(a[fx]);vec[fx].push_back(x),fa[x]=fx;}}for(int i=1;i<=n;i++){a[b[i]]=(Node){sw[i]-w[i],sw[i],i};}dfs(1);for(int i=1;i<=n;i++)printf("%lld ",max(w[i],ans[i]+w[i]));return 0;
}

参考文章:
https://www.cnblogs.com/mangoyang/p/11735219.html

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

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

相关文章

P3527-[POI2011]MET-Meteors【整体二分,树状数组】

正题 题目链接:https://www.luogu.com.cn/problem/P3527 题目大意 mmm个格子形成的环&#xff0c;有nnn个集合&#xff0c;第iii个格子属于第oio_ioi​个集合&#xff0c;kkk次让环上一段的格子加上一个权值。 对于每个iii求出第iii个集合在多少次的时候它集合中的所有格子权…

.net core实践系列之短信服务-Sikiro.SMS.Api服务的实现

前言本篇会继续讲解Sikiro.SMS.Job服务的实现&#xff0c;在我写第一篇的时候&#xff0c;我就发现我当时设计的架构里Sikiro.SMS.Job这个可以选择不需要&#xff0c;而使用MQ代替。但是为了说明调度任务使用实现也坚持写了下。后面会一篇针对架构、实现优化的讲解。源码地址&a…

Drainage Ditches POJ1273

Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 93263 Accepted: 36174试题链接 文章目录Description题意&#xff1a;题解&#xff1a;代码&#xff1a;Dinic做法EK做法Description Every time it rains on Farmer John’s fields, a pond forms over Bessie’…

【主席树】可持久化数组(金牌导航 可持久化数据结构-3)

可持久化数组 金牌导航 可持久化数据结构-3 题目大意 给出一个序列a&#xff0c;让你执行若干操作&#xff0c;操作分为两种&#xff1a; 1.继承第v次操作后把第x个数改成y 2.查询第v次操作的第x个数的值 输入样例 5 10 59 46 14 87 41 0 2 1 0 1 1 14 0 1 1 57 0 1 1 88 …

[集训队作业2018] 复读机(生成函数,单位根反演)

传送门 subtask 1&#xff1a;d1d1d1 答案为knk^nkn。 subtask 2&#xff1a;n≤1000,k≤100n\leq1000,k\leq 100n≤1000,k≤100 设f[i][j]f[i][j]f[i][j]表示由iii个复读机来分jjj个时间点的方案数。 可以得到递推式&#xff1a; f[i][j]∑p0j[d∣p]Cjpf[i−1][j−p]f[i][j…

jzoj5097-[GDOI2017day1]取石子游戏【并查集,LCA】

正题 题目链接:https://gmoj.net/senior/#main/show/5097 题目大意 nnn个点的一棵树&#xff0c;每个节点有权值。对于每个点求树上所有权值去除掉他的子树的权值后的mexmexmex值。 解题思路 对于一个权值www&#xff0c;权值为www的所有点的LCALCALCA到根节点的路径上都不会…

P2756 飞行员配对方案问题【网络流24题】

P2756 飞行员配对方案问题 文章目录题目背景题解&#xff1a;代码&#xff1a;题目背景 第二次世界大战期间&#xff0c;英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的两名飞行员&#xff0c;其中一名是英国…

大数据分析中使用关系型数据库的关键点

相当一部分大数据分析处理的原始数据来自关系型数据库&#xff0c;处理结果也存放在关系型数据库中。原因在于超过99%的软件系统采用传统的关系型数据库&#xff0c;大家对它们很熟悉&#xff0c;用起来得心应手。在我们正式的大数据团队&#xff0c;数仓&#xff08;数据仓库H…

【FHQ treap】维护书架(金牌导航 无旋式treap-1)

维护书架 金牌导航 无旋式treap-1 题目大意 给出一个序列a&#xff0c;编号为1~n&#xff0c;让你做若干操作&#xff0c;操作有五种&#xff1a; 1.把第x个数放在最前面 2.把第x个数放在最后面 3.把第x个数和第x1x\pm 1x1个数交换 4.查询编号为i的数前面有多少个数 5.查询第…

P5488-差分与前缀和【NTT,生成函数】

正题 题目链接:https://www.luogu.com.cn/problem/P5488 题目大意 求一个长度为nnn的序列的kkk阶差分/前缀和。 解题思路 先考虑前缀和怎么做 搞出来生成函数就是(∑i0naixi)∗(∑i0∞xi)k(\sum_{i0}^na_ix^i)*(\sum_{i0}^{\infty}x^i)^k(i0∑n​ai​xi)∗(i0∑∞​xi)k 然…

图论复习——最小生成树MST

知识点 MST的构造 Boruvka算法常用于解决这类问题&#xff1a;给你n个点&#xff0c;每个点有点权&#xff0c;任意两个点之间有边权&#xff0c;边权为两个点权用过某种计算方式得出&#xff0c;求最小生成树。动图 MST上的确定性和存在性问题 最小生成树的两个性质&#xf…

Ocelot简易教程(二)之快速开始1

Ocelot是为.net core量身定做的&#xff0c;目前是基于 netstandard2.0进行构建的。.NET Core 2.1中如何使用呢&#xff1f;安装NuGet package使用nuget安装Ocelot及其依赖项。您需要创建一个netstandard2.0项目并将其Package安装到项目中。然后按照下面的“启动”和“ 配置”节…

【树链剖分】【线段树】树的统计(金牌导航 树链剖分-1)

树的统计 金牌导航 树链剖分-1 题目大意 给出一棵树&#xff0c;让你做若干操作&#xff0c;操作如下&#xff1a; 1.修改一个节点的值 2.查询两个节点之间路径的最大值 3.查询两个节点之间路径的和 输入样例 4 1 2 2 3 4 1 4 2 1 3 12 QMAX 3 4 QMAX 3 3 QMAX 3 2 QMAX 2…

P2761 软件补丁问题

文章目录题目描述题解&#xff1a;代码&#xff1a;添加链接描述题目描述 T 公司发现其研制的一个软件中有 n 个错误&#xff0c;随即为该软件发放了一批共 m 个补丁程序。每一个补丁程序都有其特定的适用环境&#xff0c;某个补丁只有在软件中包含某些错误而同时又不包含另一些…

P4091-[HEOI2016/TJOI2016]求和【斯特林数,NTT】

正题 题目链接:https://www.luogu.com.cn/problem/P4091 题目大意 给出nnn&#xff0c;求 ∑i0n∑j0i{ij}2jj!\sum_{i0}^n\sum_{j0}^i\begin{Bmatrix}i\\j\end{Bmatrix}2^jj!i0∑n​j0∑i​{ij​}2jj! 解题思路 看题解才知道2jj!2^jj!2jj!对这nlog⁡nn\log nnlogn做法没有任…

Xamarin中国技术社区及BXUG官网上线啦

Xamarin中国技术社区及BXUG官网为.NET开发者提供移动跨平台技术学习的园地&#xff0c;为Xamarin及.NET技术达人提供展示分享的舞台&#xff0c; 为企业CTO等技术负责人提供跨平台移动应用解决方案的交流平台&#xff01;网址链接&#xff1a;http://bxug.bopoda.cn/Xamarin中国…

MST(最小生成树)的构造

是什么&#xff1a; 一个有 n 个结点的连通图的生成树是原图的极小连通子图&#xff0c;且包含原图中的所有 n 个结点&#xff0c;并且有保持图连通的最少的边。 kruskal算法&#xff1a; #include<iostream> #include<vector> #include<algorithm> #incl…

【虚树】世界树(金牌导航 虚树-1/luogu 3233)

世界树 金牌导航 虚树-1 luogu 3233 题目大意 对于一棵树&#xff0c;给出若干询问&#xff0c;每个询问告诉你若干个特殊点&#xff0c;对于所有点&#xff0c;都会选择离自己最近&#xff08;距离相等就选编号最小的&#xff09;的特殊点&#xff0c;问对于所有特殊点&am…

用python将图片转换成二值图像

大创项目是图像识别&#xff0c;第一个任务是将一个图片转换成二值图像 之前用过python的numpy和turtle&#xff0c;这次要用到图像库PIL的类Image&#xff0c;也算是刚刚从零开始学起 整体效果&#xff08;用01串表示图像&#xff09; 原理很简单&#xff1a;将图片中黑色…

.Net Core SignalR 初体验

前言Asp.Net SignalR已经出来很久了&#xff0c;但是一直没有静下心来好好看看。昨天花了几个小时的时间看了下。首先借鉴了官方文档&#xff0c;如何搭建一个SignalR的Demo。参考文章&#xff1a;https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/signalr?viewaspnet…