题目链接:
https://jzoj.net/senior/#main/show/5926
题目:
题解:
显然最小的最大路径在最小生成树上(最小生成树=最小瓶颈生成树)
于是我们建出kruskal重构树,两个节点的d值就是lca代表的边的边权,问题转化为对于每个lca计算以它为lca的且满足$|c_u-c_v|$的点对的个数
对于每个lca我们枚举 size 较小的那棵子树内的点(每次选择size较小的暴力计算就是启发式合并),算出在另一棵子树中能与它组成点对的点的个数。这个问题实际上就是询问在 dfs 序的一段区间上并且颜色不在一段区间内的点 数,二维数点问题可以离线树状数组完成。
#include<algorithm> #include<cstring> #include<cstdio> #include<iostream> using namespace std; typedef long long ll; const int N=2e5+15; const int M=5e5+15; int n,m,xys,tot,tim,ask; ll L,mx; int fa[N<<1],in[N<<1],dfn[N<<1],siz[N<<1],lf[N<<1],rf[N<<1],ED[N<<1],t[N<<1]; ll c[N],ANS[N<<1],val[N<<1]; struct EDGE{ int u,v; ll w; }e[M]; bool operator <(EDGE a,EDGE b) {return a.w<b.w;} struct QUE{ ll x,y; int k,id; }q[N<<6]; bool operator <(QUE a,QUE b){return (a.x<b.x)||(a.x==b.x&&a.k>b.k);} inline char nc(){ static char buf[10000000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,10000000,stdin),p1==p2)?EOF:*p1++; } inline int read(){ char ch=nc();int s=0,f=1; while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=nc();} while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=nc();} return s*f; } int find(int x) { if (fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } void dfs(int x) { dfn[x]=++tim;siz[x]=1; if (x<=n) {ED[x]=dfn[x];return;} if (lf[x]) dfs(lf[x]); if (rf[x]) dfs(rf[x]); ED[x]=tim; if (siz[lf[x]]>siz[rf[x]]) swap(lf[x],rf[x]); siz[x]+=siz[lf[x]]+siz[rf[x]]; } void ASK(int x,int st,int ed,int id) { if (x<=n) { ll p1,p2; p1=0;p2=c[x]-L; if (p2>=p1) { q[++ask]=(QUE){p2,ed,1,id}; q[++ask]=(QUE){p1-1,ed,-1,id}; q[++ask]=(QUE){p2,st-1,-1,id}; q[++ask]=(QUE){p1-1,st-1,1,id}; } p1=c[x]+L;p2=mx; if (L==0) ++p1; if (p1<=p2) { q[++ask]=(QUE){p2,ed,1,id}; q[++ask]=(QUE){p1-1,ed,-1,id}; q[++ask]=(QUE){p2,st-1,-1,id}; q[++ask]=(QUE){p1-1,st-1,1,id}; } return; } if (lf[x]) ASK(lf[x],st,ed,id);if (rf[x]) ASK(rf[x],st,ed,id); } void modify(int x,int y) { while (x<=tim) { t[x]+=y; x+=x&-x; } } int query(int x) { int re=0; while (x) { re+=t[x]; x-=x&-x; } return re; } int main() { freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); n=read();m=read();L=read(); for (int i=1;i<=n;i++) c[i]=read(),mx=max(mx,c[i]),fa[i]=i; for (int i=1;i<=m;i++) { e[i].u=read();e[i].v=read();e[i].w=read(); } sort(e+1,e+1+m); for (int i=n+1;i<=n<<1;i++) fa[i]=i; int cnt=0;xys=n; for (int i=1;i<=m;i++) { int u=e[i].u,v=e[i].v; int fu=find(u),fv=find(v); if (fu!=fv) { val[++xys]=e[i].w; fa[fu]=xys;fa[fv]=xys; lf[xys]=fu;rf[xys]=fv; in[fu]++;in[fv]++; ++cnt; if (cnt==n-1) break; } } for (int i=1;i<=xys;i++) if (!in[i]) dfs(i); for (int i=1;i<=n;i++) { q[++ask]=(QUE){c[i],dfn[i],2,0}; } for (int i=n+1;i<=xys;i++) { ASK(lf[i],dfn[rf[i]],ED[rf[i]],i); } sort(q+1,q+1+ask); for (int i=1;i<=ask;i++) { if (!q[i].id) modify(q[i].y,1); else ANS[q[i].id]+=q[i].k*query(q[i].y); } ll ans=0; for (int i=n+1;i<=xys;i++) ans+=ANS[i]*1ll*val[i]; printf("%lld ",ans); return 0; }