首页 > 其他分享 >《罗必达法则》 解题报告

《罗必达法则》 解题报告

时间:2023-09-10 13:55:06浏览次数:40  
标签:sz 法则 int LL 解题 ind co 必达 s1

首先我们先考虑只询问 \(1\) 节点的情况。

那么这时候我们是一个以 \(1\) 节点为根的有根树。

这时候我们要选择 \(k\) 条路径,使得所有点到这 \(k\) 条路径其中之一的最短距离的和最小。

image

对于 \(k=2\) 我们就可以这样选。

但是直接选路径实际上不太好考虑,我们可以拆贡献,转化一下,变成每条边的贡献。

image

我们考虑 \(u\) 与他父亲相连的边的贡献是多少,如果选了他父亲这条边,那么贡献就是 \(0\) ,如果没选的话,那么贡献就是 \(u\) 子树中的 \(w\) 的和。(不存在子树里有边选了,而 \(u\) 与他父亲的边没选的情况)

这时候我们的问题就转化成了,从图中选 \(k\) 条可重路径出来,使得至少被一条路径包含的边的权值和最大,这样我们用总数减去这个最大就可以得到最小的答案。

这时候如何处理呢。

考虑贪心,假如我们只能选一条路径,我们肯定是选最大的,假如是红色这条。

image

而加入我们能选两条路径,我们第一条仍然是选择最大的,因为如果存在一种方案不选这个最大的路径,那么一定可以将一条路径调整成最大的这条,不劣。而如果存在一条路径选最大,另一条选了其他的,那么我们第一条选最大,也一定是不劣的。

所以我们最大的一定要选。

所以这样我们就可以把原树剖成若干条链,每条链的权值和就是这条路径所能获得的权值和。

image

具体长成这样。

所以我们就要维护前 \(k\) 大的链的权值和,然后加起来就是我们的答案了。

我们可以维护两个 \(multiset\) ,其中一个存的是前 \(k\) 大的,另一个存的是剩下的。

那么我们处理一次的时间复杂度是 \(O(n\log n)\)

如果对于所有点都这样处理的话,那么实际上总时间复杂度是 \(O(n^2\log n)\)

考虑进一步优化。

我们考虑换根 \(dp\) 。

image

假如从 \(u\) 走到 \(v\)

image

那么实际上就只有 \(O(1)\) 条边是被改变的,一个是原本包含 \(u\sim v\) 这条边的链的权值减少了,一个是从 \(u\) 进来的最长的边增加了 \(u\sim v\) 这条边的权值(不过这条边的权值和原本是不一样的,再算一下就好了)

所以我们只用修改两条边的权值就行了。

然后用我们上面所说的 \(multiset\) 维护前 \(k\) 大即可。

时间复杂度 \(O(n\log n)\)

`#include<bits/stdc++.h>
typedef long long LL;

using namespace std;
const int MAXN=2e5+10;
int n,k;
int a[MAXN];
vector e[MAXN];
void add(int f,int t) {
e[f].push_back(t);
}
LL sz[MAXN],co[MAXN],Fa[MAXN],maxn[MAXN],cost[MAXN],fr[MAXN],total;
//co 链的最大值
//Fa 是否是链的顶端
//maxn 最大链的方向
//cost 其他点到他的距离
//fr 可以减去的最大距离
LL ans[MAXN];
void dfs(int u,int fa) {
sz[u]=a[u];
for(auto t:e[u]) {
if(t==fa) continue;
dfs(t,u);
sz[u]+=sz[t];
if(co[t]>co[maxn[u]]) maxn[u]=t;

	cost[u]+=cost[t]+sz[t];
}
Fa[maxn[u]]=u;
co[u]=(u!=1?sz[u]:0)+co[maxn[u]];

}
multiset s1,s2;
LL sum=0;
void update(LL x) {
if(s1.size()<k) {
s1.insert(x);
sum+=x;
}
else s2.insert(x);
LL l1=s1.size(),l2=s2.size();
while(l1&&l2) {
auto it=s1.begin(),itt=s2.end();
--itt;
LL x=it,y=itt;
if(x<y) {
s1.erase(it);
s2.erase(itt);
sum+=y-x;
s1.insert(y);
s2.insert(x);
}
else break;
}
}
LL res;
void dele(LL x) {
if(s1.count(x)) {
auto it=s1.lower_bound(x);
s1.erase(it);
sum-=x;
while(s1.size()&&s2.size()) {
int l1=s1.size(),l2=s2.size();
if(l1<k) {
if(!l2) return ;
auto it=s2.end();
--it;
LL x=*it;
sum+=x;
s1.insert(x);
s2.erase(it);
}
else break;
}
}
else {
auto it=s2.lower_bound(x);
s2.erase(it);
}
}
LL mx,ind[MAXN],tot;
bool vis[MAXN];
void zx(LL x,LL y) {
dele(x);
update(y);
}
void dfs1(int u,int fa,LL FAFA,bool sf_l) {
fr[u]=sum;
int mx=0;
if(sf_l) {
for(auto t:e[u]) {
if(tfa) continue;
if(co[t]>co[mx]) mx=t;
}
FAFA=co[mx];
}
for(auto t:e[u]) {
if(t
fa||vis[t]) continue;
cost[t]=cost[u]+(total-sz[t])-sz[t];
zx(co[t],co[t]-sz[t]);
LL ls=FAFA,lss;
lss=ls+(total-sz[t]);
zx(ls,lss);
dfs1(t,u,lss,0);
zx(co[t]-sz[t],co[t]);
zx(lss,ls);
res=0;
}
}
int main () {
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i) {
scanf("%d",&a[i]);
total+=a[i];
}
for(int i=1;i<n;++i) {
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,0);
co[1]=0;
for(int i=1;i<=n;++i) {
if(!Fa[i]) {
update(co[i]);
}
}
int x=1;
while(x) {
vis[x]=1;
ind[++tot]=x;
x=maxn[x];
}
update(0);
for(int i=1;i<=tot;++i) { res=ind[i];
zx(co[ind[i]],co[maxn[ind[i]]]);
dfs1(ind[i],0,0,1);
if(i<tot) {
int j=ind[i];
co[j]=0;
for(auto t:e[j]) {
if(t==ind[i+1]) continue;
co[j]=max(co[j],co[t]);
}
zx(co[j],co[j]+total-sz[ind[i+1]]);
co[j]=co[j]+total-sz[ind[i+1]];
}
cost[ind[i+1]]=cost[ind[i]]+(total-sz[ind[i+1]])-sz[ind[i+1]];
}
for(int i=1;i<=n;++i) printf("%lld\n",cost[i]-fr[i]);
return 0;
}`

标签:sz,法则,int,LL,解题,ind,co,必达,s1
From: https://www.cnblogs.com/ddl1no2home/p/17691123.html

相关文章

  • 数据共享的黄金法则:三方系统对接必知事项
    大家好,我是小米,一个热爱技术、乐于分享的90后。今天,我要和大家聊一聊关于与三方系统对接的注意事项。在当今数字化时代,各种系统之间的对接已经成为企业不可或缺的一部分,但这并不意味着它是一件轻松的事情。如果你想确保你的对接顺利进行,那么就一定要仔细阅读这篇文章,因为我将会为大......
  • 「解题报告」[AGC007C] Pushing Balls
    非常高级的题,但是感觉官方题解的做法和洛谷大部分题解的做法都并不很能说服我,感觉根据规律发现期望序列还是等差数列有点扯了。但是zhylj的题解的做法感觉很强啊,但是他题解后面的推导感觉好像有点问题。所以整出来这样一个做法,感觉还是很清楚的。首先我们可以考虑将原问题转化......
  • 暑假模拟赛二 解题报告
    唐山一中模拟赛一解题报告\[\Large110\pts,\text{No.}1.\]打这场比赛的时候分心很多,基本上就是T1一眼了一下然后实现,然后就开始死摆。一会儿摸鱼一会儿躺着,最后的将近3个小时都在摆的过程中偶尔推一下T2。但显然T2打出了正解,但是由于一步小小的错误,加之结论出现了......
  • LeetCode952三部曲之一:解题思路和初级解法(137ms,超39%)
    欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos题目描述难度:困难编程语言:Java给定一个由不同正整数的组成的非空数组nums,考虑下面的图:有nums.length个节点,按从nums[0]到nums[nums.length-1]标记;只有当......
  • 《CF1863》 解题报告
    题面传送器首先有一个\(naive\)的做法。直接\(O(n^3)\)暴力判断。考虑寻找突破口。假如给了你一个序列,异或值为\(S\),那么实际上假如中间有一个断点\(mid\),那么我们最终决定保留哪一段,实际上是看\(S\)的最高位\(1\)的位置来比较的,所以我们只需要管最高位的\(1\)......
  • 基环树问题 解题报告
    luoguP5022旅行题意对于60%的数据,给一棵树,求一条字典序最小的Hamilton路径;对于40%的数据,给一颗基环树,求一条字典序最小的Hamilton路径。分析前向星存图,对于每个点的出边排序,从1开始dfs一遍即可过60%数据;对于基环树,由于Hamilton路径在树上必然有一条边不经过,而这条边必然......
  • 《AT_arc106_d》 解题报告
    来一道简单数论。求\(\sum\limits_{l=1}^{n-1}\sum\limits_{r=l+1}^{n}(a_l+a_r)^x\),其中\(1\lex\lek\)\(n\le2e5,k\le300\)显然是一个\(O(nk)\)的做法我们来推式子\[\begin{aligned}\sum\limits_{l=1}^{n-1}\sum\limits_{r=l+1}^{n}(a_l+a_r)^x&=\sum\li......
  • The 2021 ICPC Asia Shenyang Regional Contest 解题报告
    The2021ICPCAsiaShenyangRegionalContestsolo七题罚时738打到金尾了,但是这个G和I也应该是自己能做出来的。G找了若干性质确实转化到最后一步了。但本应该搞出的dp没有想到。G和M感觉都有点降智。而I则是被复数吓到了。有点菜。B:拆位,扩展域并查集。E:签到。F......
  • 高等数学——洛必达法则
    洛必达法则用于处理\(\frac{0}{0}\)或者\(\frac{\infty}{\infty}\)。定理1:当\(x\toa\)时,\(f(x)\to0,F(x)\to0\).在\(a\)的去心领域内\(f'(x),F'(x)\)存在,且\(F'(x)\ne0\)。\(\lim_{x\toa}\frac{f'(x)}{F'(x)}\)存在(或无穷大)。......
  • Atcoder Beginner Contest 317 解题报告
    AtcoderBeginnerContest317ABC316咋没了。暂时A~E。HintsD$\quad$可以算出每次选举需要的改票数。然后变成了一个经典问题。E$\quad$有点naive。不用担心暴力扫T掉,时间复杂度是真的。F$\quad$F1$\qquadn$这么大一维都枚举不了……诶,$a_i$只有$10$?$\qua......