线段树和DP的综合题,思路非常巧妙~~~acdream的比赛我一般都会做,因为时间点比较好,不想CF的时间。。。当时比赛的时候不会做(当时我还不会线段树,其实现在也没学好QAQ),看了题解以后补上。。。。题解在此ACdream题解链接。
#include <iostream>
#include <sstream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <climits>
#define maxn 100005
#define eps 1e-6
#define mod 1000000007
#define INF 99999999
#define lowbit(x) (x&(-x))
#define lson o<<1, L, mid
#define rson o<<1 | 1, mid+1, R
typedef long long LL;
using namespace std;
struct city
{
int x, number;
}c[maxn];
int id[maxn];
int pre[maxn];
int minv[maxn<<2];
int n, m, p, v;
int ql, qr;
void init(void)
{
memset(minv, 0, sizeof minv);
memset(pre, -1, sizeof pre);
}
int cmp(city a, city b)
{
return a.x<b.x;
}
void work(void)
{
int a, b;
for(int i=1;i<=n;i++){
scanf("%d",&c[i].x);
c[i].number=i;
}
sort(c+1, c+n+1, cmp);
for(int i=1;i<=n;i++)
id[c[i].number]=i;
for(int i=1;i<=m;i++){
scanf("%d%d", &a, &b);
a=id[a], b=id[b];
if(a>b) swap(a, b);
pre[b]=max(pre[b], a);
}
}
void updata(int o, int L, int R)
{
if(L==R){
minv[o]=v;
return;
}
int mid=(R+L)>>1;
if(p<=mid) updata(lson);
else updata(rson);
minv[o]=min(minv[o<<1], minv[o<<1 | 1]);
}
int query(int o, int L, int R)
{
if(ql<=L && qr>=R) return minv[o];
int mid=(R+L)>>1, ans=INF;
if(ql<=mid) ans=min(ans, query(lson));
if(qr>mid) ans=min(ans, query(rson));
return ans;
}
void solve(void)
{
int limit=0, dp=0;
for(int i=1;i<=n;i++){
if(pre[i]!=-1) limit=max(pre[i], limit);
ql=limit, qr=i-1;
if(ql>=1 && qr>=1) dp=query(1, 1, n);
p=i, v=dp+c[i+1].x-c[i].x;
updata(1, 1, n);
}
printf("%d\n", dp);
}
int main(void)
{
while(scanf("%d%d",&n,&m)!=EOF){
init();
work();
solve();
}
return 0;
}