额呵呵呵
【题目分析】
我选择死亡。。。。。。。。我的天哪ldx大佬竟然吊打了标程?究竟是。。还是。。
蒟蒻只能暴力枚举拿着30分滚粗。。。点分治是什么?完全没想到好吗。。。。。
首先最后能做出贡献的边一定是在最小生成树上,这个应该不需要证吧。。。。。
然后考虑在加边的过程中,连接两个联通块能产生的贡献就是两个联通块内满足限制的点对数*边权,所以计算还是很容易的。
然后考虑如何去寻找一个点与其满足限制的点对。这里选择主席树,每次只要查找比col[i]-L小的与col[i]+L大的即可。
求完贡献后考虑合并两个联通块的信息,直接启发式合并即可,将size小的直接往size大的联通块加就行了。
(一点小建议:不要随便全局long long!容易TLE!)
【代码~】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=2e5+10;
const int MAXM=1e6+10;
int n,m,cnt,tot,k,maxx;
int col[MAXN],siz[MAXN],fa[MAXN],rt[MAXN];
struct Edge{
int from,to,w;
friend inline bool operator<(const Edge &a,const Edge &b){
return a.w<b.w;
}
}graph[MAXM],edge[MAXM];
struct Tree{
int l,r;
int sum;
}tr[MAXN*50];
struct node{
int fa,color;
friend inline bool operator<(const node &a,const node &b){
if(a.fa==b.fa)
return a.color<b.color;
return a.fa<b.fa;
}
};
vector<node> vec[MAXN];
inline int Read()
{
int i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
void insert(int &root,int l,int r,int x,int key)
{
if(!root)
root=++tot;
tr[root].sum+=key;
if(l==r)
return ;
int mid=l+r>>1;
if(x<=mid)
insert(tr[root].l,l,mid,x,key);
else
insert(tr[root].r,mid+1,r,x,key);
}
int merge(int x,int y,int l,int r)
{
if(!x||!y)
return x+y;
int mid=l+r>>1;
tr[x].l=merge(tr[x].l,tr[y].l,l,mid);
tr[x].r=merge(tr[x].r,tr[y].r,mid+1,r);
tr[x].sum+=tr[y].sum;
return x;
}
int query(int root,int l,int r,int L,int R)
{
if(l>R||r<L)
return 0;
if(L<=l&&r<=R)
return tr[root].sum;
int mid=l+r>>1;
if(R<=mid)
return query(tr[root].l,l,mid,L,R);
else
{
if(L>mid)
return query(tr[root].r,mid+1,r,L,R);
else
return query(tr[root].l,l,mid,L,mid)+query(tr[root].r,mid+1,r,mid+1,R);
}
}
inline int solve(int root,int x,int k)
{
int s=0,t=maxx;
return query(root,0,maxx,max(s,x-k+1),min(x+k-1,t));
}
inline int find(int x)
{
if(x==fa[x])
return x;
return fa[x]=find(fa[x]);
}
inline void kruskal()
{
for(int i=1;i<=n;++i)
fa[i]=i;
sort(graph+1,graph+m+1);
int sum=0;
for(int i=1;i<=m;++i)
{
int u=graph[i].from,v=graph[i].to;
u=find(u),v=find(v);
if(u==v)
continue;
sum++;
fa[v]=u;
edge[++cnt]=graph[i];
if(sum==n-1)
break;
}
}
inline void hebing(int x,int y)
{
int siz1=vec[x].size();
for(int i=0;i<siz1;++i)
vec[y].push_back(vec[x][i]);
rt[y]=merge(rt[y],rt[x],0,maxx);
fa[x]=y;
siz[y]+=siz[x];
}
int main()
{
n=Read(),m=Read(),k=Read();
for(int i=1;i<=n;++i)
col[i]=Read(),maxx=max(maxx,col[i]);
for(int i=1;i<=m;++i)
graph[i].from=Read(),graph[i].to=Read(),graph[i].w=Read();
kruskal();
tot=n;
for(int i=1;i<=n;++i)
{
fa[i]=i,siz[i]=1;
node x;
x.fa=i,x.color=col[i];
vec[i].push_back(x);
rt[i]=i;
insert(rt[i],0,maxx,col[i],1);
}
LL ans=0;
for(int i=1;i<=cnt;++i)
{
int u=edge[i].from,v=edge[i].to;
int fu=find(u),fv=find(v);
if(siz[fu]>siz[fv])
swap(fu,fv),swap(u,v);
int siz1=vec[fu].size(),siz2=vec[fv].size();
for(int j=0;j<siz1;++j)
{
LL tmp=(siz2-solve(rt[fv],vec[fu][j].color,k));
ans+=edge[i].w*tmp;
}
hebing(fu,fv);
}
cout<<ans;
return 0;
}