线段树和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; }