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)的话,会超时,所以求最小值是采用线段树优化(另开一个数组);

线段树单点更新,区间求极值;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
int dp[5000100];
int num[5000100];
int n,m;
int s[5000100],t[5000100];
void build(int l,int r,int pos){
      num[pos]=dp[pos]=inf;
      if(l==r){
        return;
    }
    int mid=(l+r)/2;
    build(l,mid,pos*2);
    build(mid+1,r,pos*2+1);
}
void update(int p,int val,int l,int r,int pos){
   if(dp[pos]>val) dp[pos]=val;
   if(l!=r){
      int mid=(l+r)/2;
      if(p<=mid) update(p,val,l,mid,pos*2);
      else if(mid<p) update(p,val,mid+1,r,pos*2+1);
   }
}
int query(int L,int R,int l,int r,int pos){
    if(L<=l&&r<=R){
        return dp[pos];
    }
    int mid=(l+r)/2;
    if(R<=mid) return query(L,R,l,mid,pos*2);
    else if(mid<L) return query(L,R,mid+1,r,pos*2+1);
    else{
        int t1,t2;
        t1=query(L,R,l,mid,pos*2);
        t2=query(L,R,mid+1,r,pos*2+1);
        return min(t1,t2);
    }
}
int main(){
   int i,j,k;
   while(scanf("%d%d",&n,&m)!=EOF){
      build(1,n,1);
      for(i=0;i<m;i++){
        scanf("%d%d",&s[i],&t[i]);
      }
      num[1]=0;
      update(1,0,1,n,1);
      for(i=0;i<m;i++){
        int v=min(num[t[i]],query(s[i],t[i]+1,1,n,1)+1);
        num[t[i]]=v;
        update(t[i],v,1,n,1);
      }
      printf("%d\n",num[n]);
   }
   return 0;
}
时间: 2024-12-29 23:23:55

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 ( 线段树 &amp;&amp; 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 ) 表示 则状态转移方程为 (

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 2528 Mayor&#39;s posters (线段树区间更新+离散化)

题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值.由于l和r范围比较大,内存就不够了,所以就用离散化的技巧 比如将1 4化为1 2,范围缩小,但是不影响答案. 写了这题之后对区间更新的理解有点加深了,重点在覆盖的理解(更新左右两个孩子节点,然后值清空),还是要多做做题目. 1 #include <iostream> 2 #include <

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d

poj 2777 Count Color(线段树区间修改)

题目链接:http://poj.org/problem?id=2777 题目意思:就是问你在询问的区间里有几种不同的颜色 思路:这题和一般的区间修改差不多,但是唯一不同的就是我们要怎么计算有种颜色,所以这时候我们就需要把延时标记赋予不同的意义,当某段区间有多种颜色时就赋值为-1,当为一种颜色时就把它赋值为这个颜色的号数.这儿我们要怎么统计询问区间不同的颜色数叻,为了不重复计算同一种颜色,那么我们就需要用一个数组来标记计算过的颜色,当我们下次遇到时就不需要再次计算了.... 代码核心处就在计数那儿

poj 3368 Frequent values(线段树解法)

题目链接:http://poj.org/problem?id=3368 题目大意:给你一段不下降的序列,求给定区间里出现次数最多的那个数字的次数. 思路:首先看到这题时,第一感觉线段树,但是仔细一看问题来啦,用线段数我怎么才能计算出某段区间里出现的那个数,因为出现最多的那个数可能不是在他它的左儿子上也不是在它的右儿子上,可能在当他们合并成一个区间时就出现啦,但是这儿我们需要注意的就是,题目给的是一段不下降的序列,那么突破口就出来啦,因为如果出现相同的数字,那么它们一定是连续的.所以我们只需要在普

POJ 1436 Horizontally Visible Segments (线段树&amp;#183;区间染色)

题意   在坐标系中有n条平行于y轴的线段  当一条线段与还有一条线段之间能够连一条平行与x轴的线不与其他线段相交  就视为它们是可见的  问有多少组三条线段两两相互可见 先把全部线段存下来  并按x坐标排序  线段树记录相应区间从右往左当前可见的线段编号(1...n)  超过一条就为0  然后从左往右对每条线段  先查询左边哪些线段和它是可见的  把可见关系存到数组中  然后把这条线段相应区间的最右端可见编号更新为这条线段的编号  最后暴力统计有多少组即可了 #include <cstdio>

Poj 2528 Mayor&#39;s posters (线段树+离散化)

题目连接: http://poj.org/problem?id=2528 题目大意: 有10000000块瓷砖,n张海报需要贴在墙上,每张海报所占的宽度和瓷砖宽度一样,长度是瓷砖长度的整数倍,问按照所给海报顺序向瓷砖上贴海报,最后有几张海报是可见的? 解题思路: 因为瓷砖块数和海报张数多,首选线段树,如果按照常规的建树方式,把瓷砖当做数的节点,肯定会MTL......... 所以我们可以用海报的起点和终点当做树的节点,这样树的节点才有20000个,但是这样建树的话,求海报覆盖了那些节点会很复杂,