来自FallDream的博客,未经允许,请勿转载, 谢谢。


传送门

考虑直接维护一个堆,然后往里面丢链,并且取出k个堆顶就行了。

然后就需要分类讨论啥的,给你的三个点变成两条链,每次取出一条链之后选择权值最小的再劈成两条链丢进去。

卡空间  所以树剖,不选择倍增

复杂度O((n+k)logn)

#include<iostream>
#include<cstdio>
#include<queue>
#define MN 500000
#define N 524288
#define ll long long
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
struct data{int x,y;ll X;
friend bool operator <(const data&x,const data&y){return x.X>y.X;}
data operator + (ll y)
{
data c=*this;c.X+=y;
return c;
}
};
priority_queue<data> q;
int n,k,w[MN+],dep[MN+],head[MN+],cnt=,top[MN+],mx[MN+];
int s[MN+],p[MN+],fa[MN+],T[N*+],dfn[MN+],dn=;
struct edge{int to,next;}e[MN+];
inline void ins(int f,int t){e[++cnt]=(edge){t,head[f]};head[f]=cnt;}
vector<data>v[MN+];
int Merge(int x,int y){return w[x]>w[y]?y:x;}
int query(int l,int r)
{
int sum=;
for(l+=N-,r+=N+;l^r^;l>>=,r>>=)
{
if(~l&) sum=Merge(sum,T[l+]);
if( r&) sum=Merge(sum,T[r-]);
}
return sum;
}
inline int Up(int x,int k)
{
int z=dep[x]-k;
for(;dep[top[x]]>z;x=fa[top[x]]);
return p[dfn[top[x]]+z-dep[top[x]]];
}
int lca(int x,int y)
{
for(;top[x]!=top[y];x=fa[top[x]])
if(dep[top[x]]<dep[top[y]]) swap(x,y);
return dep[x]<dep[y]?x:y;
} pair<int,int> Query(int x,int y)
{
int res=;
for(;top[x]!=top[y];x=fa[top[x]])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
res=Merge(res,s[x]);
}
if(dfn[x]>dfn[y]) swap(x,y);
res=Merge(res,query(dfn[x],dfn[y]));
return make_pair(x,res);
} data Insert(int x,int y,ll v)
{
// cout<<"Insert"<<x<<" "<<y<<" "<<v<<endl;
pair<int,int> z=Query(x,y);
// cout<<"CalcOK"<<z.first<<" "<<z.second<<endl;
return (data){x,y,w[z.second]}+v;
} void Solve(int x,int y,int z,int l,ll Add)
{
// cout<<"Solve"<<x<<" "<<y<<" "<<z<<" "<<l<<" "<<Add<<endl;
if(z==l)
{
if(x!=z) q.push(Insert(x,Up(x,dep[x]-dep[z]-),Add));
if(y!=z) q.push(Insert(y,Up(y,dep[y]-dep[z]-),Add));
return;
}
if(!(dep[x]>=dep[z]&&Up(x,dep[x]-dep[z])==z)) swap(x,y);
if(x!=z) q.push(Insert(x,Up(x,dep[x]-dep[z]-),Add));
q.push(Insert(fa[z],y,Add));
} void Dfs(int x,int tp)
{
top[x]=tp;p[dfn[x]=++dn]=x;
if(tp==x) s[x]=x; else s[x]=Merge(s[fa[x]],x);
if(mx[x]) Dfs(mx[x],tp);
for(int i=head[x];i;i=e[i].next)
if(e[i].to!=mx[x]) Dfs(e[i].to,e[i].to);
} void Pre(int x)
{
top[x]=;mx[x]=;
for(int i=head[x];i;i=e[i].next)
{
Pre(e[i].to);
top[x]+=top[e[i].to];
if(top[e[i].to]>top[mx[x]]) mx[x]=e[i].to;
}
} int main()
{
n=read();k=read();w[]=1e9;
for(int i=;i<=n;++i) w[i]=read(),q.push((data){i,i,w[i]});
for(int i=;i<=n;++i) ins(fa[i]=read(),i),dep[i]=dep[fa[i]]+;
Pre();Dfs(,);
for(int i=;i<=n;++i) T[i+N]=p[i];
for(int i=N;i;--i) T[i]=Merge(T[i<<],T[i<<|]);
for(int i=;i<=n;++i)
{
int x=read(),y=read(),z=read();
if(x==y&&y==z){v[i].push_back((data){x,x,w[x]});continue;}
if(x==y) swap(x,z);v[i].push_back(Insert(x,y,));
if(z==y||z==x) continue;
int l1=lca(x,z),l2=lca(y,z),L=lca(x,y);
if(dep[z]<dep[L]) v[i].push_back(Insert(fa[L],z,));
else if(z!=l1&&z!=l2)
{
if(dep[l1]<dep[l2]) swap(l1,l2);
int Z=Up(z,dep[z]-dep[l1]-);
v[i].push_back(Insert(z,Z,));
}
}
for(int i=;i<=k;++i)
{
data x=q.top();q.pop();printf("%lld\n",x.X);int z=Query(x.x,x.y).second;
//printf("%d %d %d %d %lld\n",x.x,x.y,x.l,x.z,x.X);
Solve(x.x,x.y,z,lca(x.x,x.y),x.X-w[z]);
for(int j=;j<v[z].size();++j) q.push(v[z][j]+x.X);
}
return ;
}

[UOJ UR #4追击圣诞老人]的更多相关文章

  1. UOJ#53. 【UR #4】追击圣诞老人 树链剖分 k短路

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ53.html 题意 给定一棵有 n 个节点的树. 每一个点有一个权值. 对于每一个 $i$ 给定三个参数 ...

  2. [UOJ UR #2]树上GCD

    来自FallDream的博客,未经允许,请勿转载,谢谢. 传送门 看完题目,一般人都能想到 容斥稳了 .这样我们只要统计有多少点对满足gcd是i的倍数. 考虑长链剖分,每次合并的时候,假设我已经求出轻 ...

  3. [UOJ UR#16]破坏发射台

    来自FallDream的博客,未经允许,请勿转载,谢谢. 传送门 先考虑n是奇数的情况,很容易想到一个dp,f[i][0/1]表示转移到第i个数,第i个数是不是第一个数的方案数,然后用矩阵乘法优化一下 ...

  4. UOJ UR#9 App管理器

    题目传送门 题目大意大概就是给你一个混合图(既有有向边又有无向边),对于每条无向边,u-v,问删去u->v,或删去v->u那条可以使新图强连通.(保证数据有解). 这道题前几个数据点送分. ...

  5. 【UOJ#33】【UR#2】树上GCD 有根树点分治 + 容斥原理 + 分块

    #33. [UR #2]树上GCD 有一棵$n$个结点的有根树$T$.结点编号为$1…n$,其中根结点为$1$. 树上每条边的长度为$1$.我们用$d(x,y)$表示结点$x,y$在树上的距离,$LC ...

  6. uoj #118. 【UR #8】赴京赶考 水题

    #118. [UR #8]赴京赶考 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/118 Description ...

  7. uoj #31. 【UR #2】猪猪侠再战括号序列 贪心

    #31. [UR #2]猪猪侠再战括号序列 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/31 Descript ...

  8. UOJ 241. 【UR #16】破坏发射台 [矩阵乘法]

    UOJ 241. [UR #16]破坏发射台 题意:长度为 n 的环,每个点染色,有 m 种颜色,要求相邻相对不能同色,求方案数.(定义两个点相对为去掉这两个点后环能被分成相同大小的两段) 只想到一个 ...

  9. 【UOJ#51】【UR #4】元旦三侠的游戏(博弈论)

    [UOJ#51][UR #4]元旦三侠的游戏(博弈论) 题面 UOJ 题解 考虑暴力,\(sg[a][b]\)记录\(sg\)函数值,显然可以从\(sg[a+1][b]\)和\(sg[a][b+1]\ ...

随机推荐

  1. formidable 表单文件和数据提交

    只要涉及文件上传,那么form标签要加一个属性: <form action="http://127.0.0.1/dopost" method="post" ...

  2. JUnit单元测试遇到的问题及解决思路

    JUnit是Java单元测试框架,我们在对开发的系统进行单元测试的时候,也遇到了如何测试多个测试用例的问题.  背景:我们的所有测试用例都保存在Excel文件中,该文件包含测试用例和预期输出.我们希望 ...

  3. RAID 损坏后如何对物理硬盘做完整镜像

    "磁盘阵列是由很多价格较便宜的磁盘,组合成一个容量巨大的磁盘组,利用个别磁盘提供数据所产生加成效果提升整个磁盘系统效能.利用这项技术,将数据切割成许多区段,分别存放在各个硬盘上." ...

  4. 泛型的 typeof

    static void Main(string[] args) { TestTypeOf<string>(); Console.ReadKey(); } static void TestT ...

  5. YML(2)yml 语法

    YAML 语法 来源:yaml 这个页面提供一个正确的 YAML 语法的基本概述, 它被用来描述一个 playbooks(我们的配置管理语言). 我们使用 YAML 是因为它像 XML 或 JSON ...

  6. Spring Security 入门(1-3-1)Spring Security - http元素 - 默认登录和登录定制

    登录表单配置 - http 元素下的 form-login 元素是用来定义表单登录信息的.当我们什么属性都不指定的时候 Spring Security 会为我们生成一个默认的登录页面. 如果不想使用默 ...

  7. python 面向对象进阶之内置方法

    一 isinstance(obj,cls)和issubclass(sub,super) 1.1,isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(obj ...

  8. NOPI实现导入导出泛型List,支持自定义列

    概述 业务上需要自定义列的Excel的导入导出,在网上看了好多资料,很多都是有Bug而且都是支持Excel和DataTable的转换,所以自己总结了一下,应用.NET平台上的NPOI封装了支持自定义列 ...

  9. 基于JWT标准的用户认证接口实现

    前面的话 实现用户登录认证的方式常见的有两种:一种是基于 cookie 的认证,另外一种是基于 token 的认证 .本文以基于cookie的认证为参照,详细介绍JWT标准,并实现基于该标签的用户认证 ...

  10. Python django实现简单的邮件系统发送邮件功能

    Python django实现简单的邮件系统发送邮件功能 本文实例讲述了Python django实现简单的邮件系统发送邮件功能. django邮件系统 Django发送邮件官方中文文档 总结如下: ...