前言
这道题总思考时间不到 (1) 分钟,获得了 (0pt) 的好成绩!
原因竟是我在 T3 试图用 (O(n)) 的时间解决二维偏序问题!
题目
( m 4s 256MB.)
( t PPL) 在做不出来题的时候喜欢随机游走。
可以将 ( m ZBQC) 看做有 (n) 个点的有向完全图,每个点有一个权值 (a_u),表示 (u ightarrow v) 的边权。
但是 ( m ZBQC) 并不是一成不变的,它有时候也会翻新,当然次数很少,具体的,它接下来有 (m) 翻新操作,每次操作会更改一条边的边权。
这天 ( t PPL) 在随机游走的时候想到一个问题,如果他把所有点对 ((i,j)) 之间的最短路都走一遍,总路程是多少?
显然 ( t PPL) 不会算,只能交给你了。
(1le nle 10^5;1le mle 3000;0le a_ile 10^6.)
讲解
从数据范围入手,我们发现 (m) 很小,和 (n) 不是一个数量级,思考有什么用。
这里大概有个经典 ( t Trick),在这种完全图中,存在一些特殊的边/点(比如这道题就是存在一些改了的边),一般来说这样构成的连通块会比较小,把这些特殊的边/点构成的连通块处理一下,再处理一下块与块之间的信息,题就解决了。
这玩意好像之前碰到过一次,不然我为什么觉得是经典 Trick。
回到这道题,考虑把每个弱连通块内部的最短路处理出来,显然连通块总大小不会超过 (m)。这时我们可以枚举起点,再用线段树优化 ( t dijkstra) 来得到块内的最短路,注意块内的最短路不一定只在块内走,有可能出块再入块,这种情况下一定是出去到一个最小的 (a) 再回来,然后我们就得到了块内的贡献。
出块的贡献就很简单了,只需要在块内找一个最优的点出去即可。
时间复杂度 (O(n+m^2log_2m))。
据说有个坑点:一条边可能会被修改多次,要取最后那次。不知道数据有没有这样的情况,反正我判了一下。
代码
不卡常!
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 100005;
const int INF = 0x3f3f3f3f;
int n,m;
int a[MAXN],suf[MAXN];
LL ans;
LL Read()
{
LL x = 0,f = 1; char c = getchar();
while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
struct edge
{
int v,w;
bool operator < (const edge &px)const{
return v < px.v;
}
};
set<edge> G[MAXN];
int f[MAXN];
int findSet(int x){if(f[x]^x)f[x]=findSet(f[x]);return f[x];}
vector<int> p[MAXN];
#define lc (x<<1)
#define rc (x<<1|1)
int MIN[MAXN<<2],ID[MAXN<<2],lz[MAXN<<2];
void calc(int x,int val){if(MIN[x]^(INF+1))MIN[x] = Min(MIN[x],val),lz[x] = Min(lz[x],val);}
void up(int x)
{
if(MIN[lc] <= MIN[rc]) MIN[x] = MIN[lc],ID[x] = ID[lc];
else MIN[x] = MIN[rc],ID[x] = ID[rc];
}
void down(int x)
{
if(lz[x] == INF) return;
calc(lc,lz[x]); calc(rc,lz[x]);
lz[x] = INF;
}
void Build(int x,int l,int r,int now)
{
lz[x] = INF;
if(l == r) {if(l^now)MIN[x] = INF;else MIN[x] = 0;ID[x] = l;return;}
int mid = (l+r) >> 1;
Build(lc,l,mid,now); Build(rc,mid+1,r,now);
up(x);
}
void Change(int x,int l,int r,int ql,int qr,int val)
{
if(ql > qr) return;
if(ql <= l && r <= qr) {calc(x,val);return;}
int mid = (l+r) >> 1;
down(x);
if(ql <= mid) Change(lc,l,mid,ql,qr,val);
if(mid+1 <= qr) Change(rc,mid+1,r,ql,qr,val);
up(x);
}
void fk(int x,int l,int r,int pos)
{
if(l == r){MIN[x] = INF+1;return;}//INF+1 : unchangeable
int mid = (l+r) >> 1;
down(x);
if(pos <= mid) fk(lc,l,mid,pos);
else fk(rc,mid+1,r,pos);
up(x);
}
int dis[MAXN],to[MAXN];
int main()
{
// freopen("happybean.in","r",stdin);
// freopen("happybean.out","w",stdout);
n = Read(); m = Read();
for(int i = 1;i <= n;++ i) a[i] = Read(),f[i] = i;
for(int i = 1;i <= m;++ i)
{
int u = Read(),v = Read(),w = Read();
int U = findSet(u),V = findSet(v);
if(U > V) f[U] = V;
else f[V] = U;
auto it = G[u].lower_bound(edge{v,0});
if(it->v == v) G[u].erase(it);
G[u].insert(edge{v,w});
}
for(int i = 1;i <= n;++ i) p[findSet(i)].emplace_back(i);
suf[n+1] = INF;
for(int i = n;i >= 1;-- i)
{
suf[i] = suf[i+1];
for(auto A : p[i]) suf[i] = Min(suf[i],a[A]);
}
for(int i = 1,nowmin = INF;i <= n;++ i)
{
if(!p[i].size()) continue;
for(int j = 0,N = p[i].size()-1;j <= N;++ j) to[p[i][j]] = j;
for(int j = 0,N = p[i].size()-1;j <= N;++ j)//begining
{
Build(1,0,N,j);
for(int k = 0;k <= N;++ k)//dijkstra : pop queue
{
int now = ID[1],lst = 0,x = p[i][now]; dis[now] = MIN[1];
for(auto A : G[p[i][now]])
{
Change(1,0,N,lst,to[A.v]-1,dis[now]+a[x]);
Change(1,0,N,to[A.v],to[A.v],dis[now]+A.w);
lst = to[A.v]+1;
}
if(lst <= N) Change(1,0,N,lst,N,dis[now]+a[x]);
fk(1,0,N,now);
}
int wdnmd = a[p[i][j]]+Min(nowmin,suf[i+1]);
for(int k = 0;k <= N;++ k) dis[k] = Min(dis[k],wdnmd);
int v = INF;
for(int k = 0;k <= N;++ k) ans += dis[k],v = Min(v,dis[k]+a[p[i][k]]);//inside
ans += v * (n-N-1ll);//outside
}
for(auto A : p[i]) nowmin = Min(nowmin,a[A]);
}
Put(ans,'
');
return 0;
}