1. 程式人生 > >【2018/10/26測試T2】naive的圖

【2018/10/26測試T2】naive的圖

【題目】

傳送門

【分析】

%%% ldxldx太強了 %%%

巨佬部落格

這裡就簡單說一下主要思想吧

首先由題意可知,兩個點之間的貢獻就是瓶頸邊的權值

那麼肯定就會用到最小生成樹啦,而在 kruskalkruskal 的過程中,對於兩個連通塊,當前的邊就是它們的瓶頸邊

現在問題就是如何統計出兩個連通塊的貢獻

將題目中的式子變一下形,設 CuCvL|Cu−Cv|≥L 中較大的數為 xx,較小的數為 yy,簡單移項可得 x>y+L1x>y+L−1

那麼對於所有點,我們將 CiC_iC

i+L1C_i+L−1 共同離散化,然後對 CiC_iCi+L1C_i+L−1 分別維護兩種權值線段樹,之後直接線段樹合併就行了。

時間複雜度 O(nlog  n)(n*log\;n)

【程式碼】

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define M 500005
using namespace std;
int n,m,L,num,
tot; long long ans=0; int father[N],val[N<<1],size[N*40],col[N][2],root[N][2],son[N*40][2]; struct edge { int u,v,w; }a[M]; bool comp(const edge &p,const edge &q) { return p.w<q.w; } int find(int x) { if(father[x]!=x) father[x]=find(father[x]); return father[x]; } void update(int
&root,int l,int r,int val) { if(!root) root=++tot; ++size[root]; if(l==r) return; int mid=(l+r)>>1; if(val<=mid) update(son[root][0],l,mid,val); else update(son[root][1],mid+1,r,val); } void query(int x,int y,int l,int r,int w) { if(!x||!y||l==r) return; int mid=(l+r)>>1; ans+=1ll*w*size[son[x][0]]*size[son[y][1]]; query(son[x][0],son[y][0],l,mid,w); query(son[x][1],son[y][1],mid+1,r,w); } int Merge(int x,int y,int l,int r) { if(!x||!y) return x+y; size[x]+=size[y]; if(l==r) return x; int mid=(l+r)>>1; son[x][0]=Merge(son[x][0],son[y][0],l,mid); son[x][1]=Merge(son[x][1],son[y][1],mid+1,r); return x; } int main() { // freopen("graph.in","r",stdin); // freopen("graph.out","w",stdout); int x,y,i,k; scanf("%d%d%d",&n,&m,&L); for(i=1;i<=n;++i) scanf("%d",&col[i][0]),father[i]=i; for(i=1;i<=n;++i) val[++num]=col[i][0],val[++num]=col[i][1]=col[i][0]+L-1; for(i=1;i<=m;++i) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w); sort(a+1,a+m+1,comp),sort(val+1,val+num+1),k=unique(val+1,val+num+1)-(val+1); for(i=1;i<=n;++i) { col[i][0]=lower_bound(val+1,val+k+1,col[i][0])-val; col[i][1]=lower_bound(val+1,val+k+1,col[i][1])-val; update(root[i][0],1,k,col[i][0]),update(root[i][1],1,k,col[i][1]); } for(i=1;i<=m;++i) { x=find(a[i].u); y=find(a[i].v); if(x==y) continue; father[x]=y; if(!L) ans+=1ll*a[i].w*size[root[x][0]]*size[root[y][0]]; else query(root[x][1],root[y][0],1,k,a[i].w),query(root[y][1],root[x][0],1,k,a[i].w); root[y][0]=Merge(root[y][0],root[x][0],1,k); root[y][1]=Merge(root[y][1],root[x][1],1,k); } printf("%lld",ans); // fclose(stdin); // fclose(stdout); return 0; }