码迷,mamicode.com
首页 > 其他好文 > 详细

poj 1769 Minimizing maximizer(dp+线段树)

时间:2015-08-15 06:43:46      阅读:90      评论:0      收藏:0      [点我收藏+]

标签:

题意:数列长度为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;
}

 

poj 1769 Minimizing maximizer(dp+线段树)

标签:

原文地址:http://www.cnblogs.com/dominatingdashuzhilin/p/4731634.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!