POJ 1769 Minimizing maximizer ( 线段树 && DP )

题意 : 给定一个区间长度 n ,接下来给出 m 个子区间,要求最少选出多少个区间才能使得 1~n 这个区间被所选的所有子区间覆盖

分析 : 

暴力枚举所有可能的组合可以达到 O( m^m ) ,完全不行

这里考虑动态规划解法

定义 dp[i][j] : 到第 i 个为止,完全覆盖点(即从 1~这个点都能保证被覆盖)到达第 j 个位置所需的最少子区间

则初始化为 dp[0][2~n] = INF、dp[0][1] = 0

假设当前第 i 个子区间用 ( si,ti ) 表示

则状态转移方程为

(ti ≠ j) ==> dp[i+1][j] = dp[i][j]

(ti = j) ==> dp[i+1][j] = min( dp[i][j],min( dp[i][j‘] )+1 ) ( si ≤ j‘ ≤ ti )

可以看出如果当前计算的是第 i 个则 dp 方程只和 i-1 有关系,所以可以用一维数组来优化空间

dp[ti] = min( dp[ti],min( dp[j‘] ) + 1 ) ( si ≤ j‘ ≤ ti )

而如果是要求找出一个区间的最小值的话,我们可以使用线段树来维护,让复杂度降到 logn 级别

#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 5e4 + 10;//maxn = 线段的最大长度 则=> maxn<<2 = 线段树可能的最多结点
const int INF = 0x3f3f3f3f;
int minv[maxn<<2];//保存最小值
int dp[maxn];
int L[500005], R[500005];

void PushUP(int rt) { minv[rt] = min(minv[rt<<1], minv[rt<<1|1]); }
void build(int l,int r,int rt) {//设置初始值
    if (l == r) {
        minv[rt] = INF;
        return ;
    }
    int m = l + ((r - l)>>1);
    build(lson);
    build(rson);
    PushUP(rt);
}
void update(int p,int sc,int l,int r,int rt) {//单点更新,参数(更新点,更新值,总区间左端点,总区间右端点,根节点编号)
    if (l == r) {
        minv[rt] = sc;
        return ;
    }
    int m = l + ((r - l)>>1);
    if (p <= m) update(p , sc , lson);
    else update(p , sc , rson);
    PushUP(rt);
}
 int query(int L,int R,int l,int r,int rt) {//查询最大值的写法、最小值同理、求和区间写法在下面
     if (L <= l && r <= R)
         return minv[rt];

     int m = (l + r) >> 1;
     int ret = INF;
     if (L <= m) ret = min(ret , query(L , R , lson));
     if (R > m) ret = min(ret , query(L , R , rson));
     return ret;
 }

int main(void)
{
    int len, n;
    while(~scanf("%d %d", &len, &n)){
        for(int i=1; i<=n; i++)
            scanf("%d %d", &L[i], &R[i]);
        build(1, len, 1);
        for(int i=1; i<=len; i++)
            dp[i] = INF;
        dp[1] = 0;
        update(1, 0, 1, len, 1);
        for(int i=1; i<=n; i++){
            int val = query(L[i], R[i], 1, len, 1) + 1;
            if(val < dp[R[i]]){
                //printf("%d %d\n", L[i], R[i]);
                update(R[i], val, 1, len, 1);
                dp[R[i]] = val;
            }
        }
        printf("%d\n", dp[len]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Rubbishes/p/8331501.html

时间: 2024-11-09 00:02:01

POJ 1769 Minimizing maximizer ( 线段树 && DP )的相关文章

POJ 1769 Minimizing maximizer(DP+zkw线段树)

[题目链接] http://poj.org/problem?id=1769 [题目大意] 给出一些排序器,能够将区间li到ri进行排序,排序器按一定顺序摆放 问在排序器顺序不变的情况下,一定能够将最大值交换到最后一位至少需要保留几个排序器 [题解] 我们发现,对于每个排序器,dp[ri]=min(dp[ri],min(dp[li]~dp[ri-1])+1) 我们用线段树对dp值进行最小值维护,顺序更新即可. [代码] #include <cstdio> #include <algorit

poj 1769 Minimizing maximizer(dp+线段树)

题意:数列长度为n,m次操作(n<=50000,m<=500000),每次操作将区间[si,ti]从小到大排序,求至少使用几次操作使数列的最后一个数与经过所有操作后相等: 思路:选取最少的操作得到最优解,一般采用dp; 假设原数列的第1个数为最大值,dp[j]表示最大值移动到第j个位置需要至少的操作数: 初始令dp[1]=0,dp[j]=inf(j>1); 对于每个i,有dp[ti]=min(dp[ti],min(dp[j](si<=j<=ti))+1); 若复杂度为O(nm

POJ 1769 Minimizing maximizer

dp[i = 前i中sorter][j = 将min移动到j位置] = 最短的sorter序列. 对于sorteri只会更新它右边端点r的位置,因此可以把数组改成一维的,dp[r] = min(dp[r],dp[j]+1), l≤j<r. 不是滑窗,单调队列用用不了,但是可以用线段树去维护这个最小值. /********************************************************* * ------------------ * * author Abyssal

POJ训练计划2777_Count Color(线段树/成段更新/区间染色)

解题报告 题意: 对线段染色,询问线段区间的颜色种数. 思路: 本来直接在线段树上染色,lz标记颜色.每次查询的话访问线段树,求出颜色种数.结果超时了,最坏的情况下,染色可以染到叶子节点. 换成存下区间的颜色种数,这样每次查询就不用找到叶子节点了,用按位或来处理颜色种数. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace

POJ训练计划1177_Picture(扫描线/线段树+离散)

解题报告 题意: 求矩形周长和. 思路: 左扫上扫,扫过了. #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; struct Seg { int lx,rx,ly,ry,h,v; friend bool operator < (Seg a,Seg b) { re

POJ训练计划2828_Buy Tickets(线段树/单点更新)

解题报告 题意: 插队完的顺序. 思路: 倒着处理数据,第i个人占据第j=pos[i]+1个的空位. 线段树维护区间空位信息. #include <iostream> #include <cstdio> #include <cstring> using namespace std; struct node { int x,v; } num[201000]; int sum[1000000],ans[201000]; void cbtree(int rt,int l,in

POJ 1151 Atlantis 扫描线+线段树

点击打开链接 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17252   Accepted: 6567 Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of pa

HDU 1540 &amp;&amp; POJ 2892 Tunnel Warfare (线段树,区间合并).

~~~~ 第一次遇到线段树合并的题,又被律爷教做人.TAT. ~~~~ 线段树的题意都很好理解吧.. 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1540 http://poj.org/problem?id=2892 ~~~~ 我的代码:200ms #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #defin

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #