来自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=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';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+5],dep[MN+5],head[MN+5],cnt=0,top[MN+5],mx[MN+5]; int s[MN+5],p[MN+5],fa[MN+5],T[N*2+5],dfn[MN+5],dn=0; struct edge{int to,next;}e[MN+5]; inline void ins(int f,int t){e[++cnt]=(edge){t,head[f]};head[f]=cnt;} vector<data>v[MN+5]; int Merge(int x,int y){return w[x]>w[y]?y:x;} int query(int l,int r) { int sum=0; for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1) { if(~l&1) sum=Merge(sum,T[l+1]); if( r&1) sum=Merge(sum,T[r-1]); } 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=0; 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]-1),Add)); if(y!=z) q.push(Insert(y,Up(y,dep[y]-dep[z]-1),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]-1),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]=1;mx[x]=0; 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[0]=1e9; for(int i=1;i<=n;++i) w[i]=read(),q.push((data){i,i,w[i]}); for(int i=2;i<=n;++i) ins(fa[i]=read(),i),dep[i]=dep[fa[i]]+1; Pre(1);Dfs(1,1); for(int i=1;i<=n;++i) T[i+N]=p[i]; for(int i=N;i;--i) T[i]=Merge(T[i<<1],T[i<<1|1]); for(int i=1;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,0)); 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,0)); else if(z!=l1&&z!=l2) { if(dep[l1]<dep[l2]) swap(l1,l2); int Z=Up(z,dep[z]-dep[l1]-1); v[i].push_back(Insert(z,Z,0)); } } for(int i=1;i<=k;++i) { data x=q.top();q.pop();printf("%lld ",x.X);int z=Query(x.x,x.y).second; //printf("%d %d %d %d %lld ",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=0;j<v[z].size();++j) q.push(v[z][j]+x.X); } return 0; }