【线段树+dp】 acdream 1074 风之国

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


你可能感兴趣的:(dp,线段树)