http://47.92.197.167:5283/contest/411/problem/3
场上当时认为是找出全局最大,全局最小,然后划分成不同类型的区间递归下去。
往前连肯定是尽量大的,往后连肯定是尽量小的
但发现这个过程会形成依赖。每个点不只连一条边,有些点不只连一次。但假如在每一次中,第一次选的必然是最优的。(和我当时的递归思路很像,区间最小必然会连向前面的那个max)
也就是说这个贪心具有局限性。但是我们可以尝试考虑这个贪心的状态数。每次贪心点数必然除2,所以必然符合
#include
using namespace std;
#define int long long
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<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
//mt19937 rand(time(0));
//mt19937_64 rand(time(0));
//srand(time(0));
#define N 300010
//#define M
//#define mo
struct node {
int x, y, w;
};
int n, m, i, j, k, T;
int x[N], f[N], mn[N][22], mx[N][22], p[N], ans;
int Log2[N], u, v, g[N], E[N];
vector<node>G;
int fa(int x) {
if(f[x]==x) return x;
return f[x]=fa(f[x]);
}
int Mx(int l, int r) {
int k = Log2[r-l+1];
if(x[mx[l][k]]>x[mx[r-(1<<k)+1][k]]) return mx[l][k];
return mx[r-(1<<k)+1][k];
}
int Mn(int l, int r) {
int k = Log2[r-l+1];
if(x[mn[l][k]]<x[mn[r-(1<<k)+1][k]]) return mn[l][k];
return mn[r-(1<<k)+1][k];
}
signed main()
{
freopen("mst.in", "r", stdin);
freopen("mst.out", "w", stdout);
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// T=read();
// while(T--) {
//
// }
n=read();
for(i=1; i<=n; ++i) x[i]=read(), f[i]=i,
mx[i][0]=mn[i][0]=i;
for(i=2; i<=n; ++i) Log2[i]=Log2[i>>1]+1;
for(k=1; k<=20; ++k)
for(i=1, j=(1<<k-1)+1; i+(1<<k)-1<=n; ++i, ++j) {
if(x[mx[i][k-1]]>x[mx[j][k-1]]) mx[i][k]=mx[i][k-1];
else mx[i][k]=mx[j][k-1];
if(x[mn[i][k-1]]<x[mn[j][k-1]]) mn[i][k]=mn[i][k-1];
else mn[i][k]=mn[j][k-1];
}
x[0]=-1e9; x[n+1]=1e9;
while(1) {
G.clear();
for(i=1; i<=n; ++i) p[i]=g[i]=E[i]=0;
for(i=1; i<=n; ++i) {
j=p[fa(i)];
if(j+1<=i-1) g[i]=Mx(j+1, i-1);
if(x[g[j]]>x[g[i]]) g[i]=g[j];
if(!g[i]) continue;
// printf("%d -> %d %d\n", i, g[i], x[i]-x[g[i]]);
G.pb({fa(i), fa(g[i]), x[i]-x[g[i]]});
p[fa(i)]=i;
}
for(i=1; i<=n; ++i) p[i]=g[i]=n+1; g[n+1]=n+1;
for(i=n; i>=1; --i) {
j=p[fa(i)];
if(i+1<=j-1) g[i]=Mn(i+1, j-1);
if(x[g[j]]<x[g[i]]) g[i]=g[j];
// printf("%d : %d %d\n", i, j, g[i]);
if(g[i]==n+1) continue;
// printf("%d -> %d %d\n", g[i], i, x[g[i]]-x[i]);
G.pb({fa(i), fa(g[i]), x[g[i]]-x[i]});
p[fa(i)]=i;
}
sort(G.begin(), G.end(), [] (node x, node y) { return x.w<y.w; });
for(auto t : G) {
u=t.x; v=t.y;
// printf(">> %d -> %d %d\n", u, v, t.w) ;
if(E[fa(u)]) continue;
if(fa(u)==fa(v)) continue;
ans+=t.w; f[fa(u)]=fa(v); E[fa(u)]=1;
// printf("# %d -> %d %d\n", u, v, t.w) ;
}
for(i=2; i<=n; ++i) if(fa(i)!=fa(i-1)) break;
if(i>n) break;
// printf("Hello World!\n");
}
printf("%lld", ans);
return 0;
}