题目链接:http://acm.uestc.edu.cn/problem.php?pid=1558
题目大意:给定n个区间[begi,endi],表示能从begi转换到endi,每个区间都有一个权值ti,现在要从1转换到大等于m的一个状态,问最少的权值,如果没办法到达那个状态,输出-1。n<=10万。
题目大意:给定n个区间[begi,endi],表示能从begi转换到endi,每个区间都有一个权值ti,现在要从1转换到大等于m的一个状态,问最少的权值,如果没办法到达那个状态,输出-1。n<=10万。
解题思路:线段树优化DP。如果n很小,那么这题有好多解法,用最短路(如果两个区间相连就添加一条边)或者朴素的N^2的DP(状态转移方程dp[endi] = min(dp[k]) + ti ,begi<=k<=endi)。这题n很大但仍然考虑用DP,因为每次状态转移都要用到前面某个区间的最小值,而这个查询操作用线段树就能以logn的复杂度完成,还有更新操作,只要更新endi这个点就可以,这就是最简单的单点更新线段树。为什么更新的时候只要更新一点就可以呢?为了达到这种效果我们按照区间的endi对所有区间排序,这样当前的endi肯定比之前的大,查询的时候是查询整个区间,那么endi那个点所在的最小权值就能反应整个区间的情况。
3
3 10
5 1 3
8 2 5
10 9 2
4 5
2 1 1
3 2 1
4 3 1
8 4 1
5 9
5 1 1
10 4 10
8 1 10
11 6 1
7 3 8
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define MAX 210000
#define int64 long long
#define INF (0xffffffffffff)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
struct node {
int beg,end,time;
}arr[MAX];
int64 ans,Min[MAX*3];
int n,m,tot,cnt,dis[MAX*3];
inline int64 min(int64 a,int64 b) {
return a<b?a:b;
}
int Binary(int x) {
int low = 1,high = tot,mid;
while (low <= high) {
mid = (low + high) >> 1;
if (dis[mid] == x) return mid;
else if (dis[mid] < x) low = mid + 1;
else high = mid - 1;
}
}
void DisCret() {
//离散化
int i;
dis[cnt++] = 1,dis[cnt++] = m;
sort(dis+1,dis+cnt);
for (i = 2; i < cnt; ++i)
if (dis[i] != dis[i-1]) dis[++tot] = dis[i];
for (i = 1; i <= n; ++i) {
arr[i].beg = Binary(arr[i].beg);
arr[i].end = Binary(arr[i].end);
}
}
int cmp(node a,node b){
if (a.end != b.end) return a.end < b.end;
else return a.beg < b.beg;
}
void Push_Up(int rt) {
Min[rt] = Min[rt<<1]<Min[rt<<1|1]?Min[rt<<1]:Min[rt<<1|1];
}
void Build_Tree(int l,int r,int rt) {
if (l == r) {
Min[rt] = l == 1 ? 0 : INF;
return;
}
int m = (l + r) >> 1;
Build_Tree(lson);
Build_Tree(rson);
Push_Up(rt);
}
int64 Query_Tree(int L,int R,int l,int r,int rt) {
if (L <= l && r <= R) return Min[rt];
int m = (l + r) >> 1;
int64 temp = INF;
if (m >= L) temp = min(temp,Query_Tree(L,R,lson));
if (m + 1 <= R) temp = min(temp,Query_Tree(L,R,rson));
return temp;
}
void Update(int L,int64 x,int l,int r,int rt) {
if (l == r) {
Min[rt] = min(Min[rt],x);
return;
}
int m = (l + r) >> 1;
if (L <= m) Update(L,x,lson);
else Update(L,x,rson);
Push_Up(rt);
}
int main()
{
int i,j,k,t,cas = 0;
scanf("%d",&t);
while (t--) {
scanf("%d%d",&n,&m);
cnt = tot = 1;
for (i = 1; i <= n; ++i) {
scanf("%d%d%d",&arr[i].end,&arr[i].beg,&arr[i].time);
dis[cnt++] = arr[i].beg,dis[cnt++] = arr[i].end;
}
DisCret(); //离散化
Build_Tree(1,tot,1); //构建线段树
sort(arr+1,arr+1+n,cmp); //排序后才没有后效性
for (i = 1; i <= n; ++i) {
int64 tp = Query_Tree(arr[i].beg,arr[i].end,1,tot,1);
if (tp == INF) continue;
Update(arr[i].end,tp+arr[i].time,1,tot,1); //dp[arr[i].end] = min(dp[k]) + arr[i].time;
}
ans = Query_Tree(Binary(m),tot,1,tot,1);
if (ans == INF) printf("Case #%d: -1\n",++cas);
else printf("Case #%d: %lld\n",++cas,ans);
}
}
本文ZeroClock原创,但可以转载,因为我们是兄弟。