poj 3419 Difference Is Beautiful (dp+二分+RMQ或者dp+离线线段树)

原创 2016年06月01日 11:29:19

Difference Is Beautiful

Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 2141 Accepted: 672
Description

Mr. Flower’s business is growing much faster than originally planned. He has now become the CEO of a world-famous beef corporation. However, the boss never lives a casual life because he should take charge of the subsidiary scattered all over the world. Every year, Mr. Flower needs to analyze the performance reports of these subsidiary companies.

Mr. Flower has N companies, and he numbered them with 0 to N – 1. All of the companies will give Mr. Flower a report about the development each year. Among all of the tedious data, only one thing draws Mr. Flower’s attention – the turnover. Turnover of a company can be represented as an integer Pi: positive one represents the amount of profit-making while negative for loss-making.

In fact, Mr. Flower will not be angry with the companies running under deficit. He thinks these companies have a large room for future development. What dissatisfy him are those companies who created the same turnover. Because in his eyes, keeping more than one companies of the same turnover is not necessary.

Now we know the annual turnover of all companies (an integer sequence Pi, the ith represents the turnover of the ith company this year.). We say a number sequence is perfect if all of its numbers are different from each other. Mr. Flower wants to know the length of the longest consecutive perfect sequence in a certain interval [L, R] of the turnover sequence, can you help him?

Input

The first line of the input contains two integers N and M. N is the number of companies. M is the number of queries. (1 ≤ N, M ≤ 200000). The second line contains N integer numbers not exceeding 106 by their absolute values. The ith of them represents the turnover of the ith company this year. The following M lines contain query descriptions, each description consists of two numbers: L, R (0 ≤ L ≤ R ≤ N – 1) and represents the interval that Mr. Flower concerned.

Output

The output contains M lines. For each query, output the length of the longest consecutive perfect sequence between [L, R]  

Sample Input

9 2
2 5 4 1 2 3 6 2 4
0 8
2 6
Sample Output

6
5
Hint

The longest perfect sequence of the first query in the sample input is ‘5 4 1 2 3 6’, so the answer for this query is 6.
Source

POJ Monthly–2007.10.06, SHOIT@ZSU


这题十分的经典,虽然我一直不是太会做这种数据结构题,看来接下去需要恶补一发数据结构和dp
这题有两种方法,一种是网上很多的dp+二分+RMQ,还有一种是学长想出来的离线线段树,因为很多区间问题都能用离线的方法解决呢,能不能用莫队我还没有想出来,而且这题20W的数据量莫队估计是过不去的

1.dp+二分+RMQ:dp就是处理dp[i]表示i位置最远能到哪个位置,然后这一段里面没有重复,非常简单,扫两遍就行了,然后考虑到一个性质,就是dp[i]是单调不减的,很明显吧,然后把idp[i]存进RMQ里,这样就能做到O(1)的查询了,然后对于每次询问的一个区间[L,R],考虑这个区间里的i,有些dp[i]肯定是超出L的,还有些idp[i]是在区间里的,所以根据单调性,可以二分找到这个临界值r,然后答案就是max(rL+1,RMQ(r+1,R))


代码:

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")

using namespace std;
#define   MAX           200005
#define   MAXN          2000005
#define   maxnode       15
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
const double pi    = acos(-1.0);
//const double inf   = 1e18;
const double eps   = 1e-8;
const LL    mod    = 1e9+7;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x){
    char c;
    while((c=getchar())<'0' || c>'9');
    x=c-'0';
    while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/

int a[MAX];
int vis[MAXN];
int dp[MAX];
int n,m;
int d[MAX][25];
void RMQ_init(){
    for(int i=1;i<=n;i++) d[i][0]=i-dp[i];
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i+(1<<j)-1<=n;i++){
            d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
        }
    }
}

int RMQ(int L,int R){
    if(L>R) return 0;
    int k=0;
    while((1<<(k+1))<=R-L+1) k++;
    return max(d[L][k],d[R-(1<<k)+1][k]);
}

int main(){
    //freopen("input.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>n>>m;
    mem(vis,0);mem(dp,0);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]+=1000000;
    for(int i=1;i<=n;i++){
        if(!vis[a[i]]) vis[a[i]]=i,dp[i]=0;
        else{
            dp[i]=vis[a[i]];
            vis[a[i]]=i;
        }
    }
    for(int i=1;i<=n;i++){
        dp[i]=max(dp[i],dp[i-1]);
    }
    RMQ_init();
    while(m--){
        int aa,bb;
        scanf("%d%d",&aa,&bb);
        aa++,bb++;
        int l=aa,r=bb;
        while(l<=r){
            int mid=(l+r)/2;
            if(dp[mid]>=aa) r=mid-1;
            else l=mid+1;
        }
        cout<<max(r-aa+1,RMQ(l,bb))<<endl;
    }
    return 0;
}

2.dp+离线线段树:dp的方法和上面一样,然后就是离线区间处理,重点在于区间怎么排序,线段树维护什么值。这方面我比较弱,参考学长的,按照区间的右端点排序,然后线段树维护什么呢,对于一个位置i,把区间[dp[i]+1,i]里都加1,这样表示区间里这些位置,被多少个(不重复出现的串)包含在里面,这里不好表述,需要自己想一下,然后查询的时候就是query(l,r),查询这个区间里,哪一个点被最多的[dp[i]+1,i]这样的区间覆盖,这样也是考虑到dp[i]是单调不减的性质呢其实,看来我离线还是太渣了otz


代码:

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")

using namespace std;
#define   MAX           200005
#define   MAXN          2000005
#define   maxnode       15
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
const double pi    = acos(-1.0);
//const double inf   = 1e18;
const double eps   = 1e-8;
const LL    mod    = 1e9+7;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x){
    char c;
    while((c=getchar())<'0' || c>'9');
    x=c-'0';
    while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/

int a[MAX];
int vis[MAXN];
int dp[MAX];
int n,m;
int maxv[MAX<<2];
int add[MAX<<2];
struct que{
    int l,r,id,ans;
}p[MAX];
bool cmp1(que a,que b){
    return a.r<b.r;
}
bool cmp2(que a,que b){
    return a.id<b.id;
}
void pushup(int rt){
    maxv[rt]=max(maxv[lrt],maxv[rrt]);
}

void pushdown(int rt){
    if(add[rt]){
        add[lrt]+=add[rt];
        add[rrt]+=add[rt];
        maxv[rrt]+=add[rt];
        maxv[lrt]+=add[rt];
        add[rt]=0;
    }
}

void build(int l,int r,int rt){
    maxv[rt]=add[rt]=0;
    if(l==r) return ;
    middle;
    build(lson);
    build(rson);
}

void update(int l,int r,int rt,int L,int R,int d){
    if(L<=l&&r<=R){
        add[rt]+=d;
        maxv[rt]+=d;
        return ;
    }
    pushdown(rt);
    middle;
    if(L<=m) update(lson,L,R,d);
    if(R>m) update(rson,L,R,d);
    pushup(rt);
}

int query(int l,int r,int rt,int L,int R){
    if(L<=l&&r<=R) return maxv[rt];
    middle;
    pushdown(rt);
    int ans=0;
    if(L<=m) ans=max(ans,query(lson,L,R));
    if(R>m) ans=max(ans,query(rson,L,R));
    pushup(rt);
    return ans;
}

int main(){
    //freopen("input.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>n>>m;
    mem(vis,0);mem(dp,0);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]+=1000000;
    for(int i=1;i<=n;i++){
        if(!vis[a[i]]) vis[a[i]]=i,dp[i]=0;
        else{
            dp[i]=vis[a[i]];
            vis[a[i]]=i;
        }
    }
    for(int i=1;i<=n;i++){
        dp[i]=max(dp[i],dp[i-1]);
    }
    build(1,n,1);
    for(int i=0;i<m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        x++,y++;
        p[i]=(que){x,y,i};
    }
    sort(p,p+m,cmp1);
    int tmp=1;
    for(int i=0;i<m;i++){
        while(tmp<=p[i].r){
            update(1,n,1,dp[tmp]+1,tmp,1);
            tmp++;
        }
        p[i].ans=query(1,n,1,p[i].l,p[i].r);
    }
    sort(p,p+m,cmp2);
    for(int i=0;i<m;i++) printf("%d\n",p[i].ans);
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

RMQ的ST写法和线段树写法两种姿势

RMQ问题为求区间最值的问题   线段树可以在O(logN)的时间复杂度内完成询问操作。 但是ST算法可以在常数时间内完成询问操作   ST算法:基于动态规划求区间最值的算法。 分为预处理...
  • u012350533
  • u012350533
  • 2013年11月09日 12:20
  • 1329

HDU 3450 线段树+二分

点击打开链接 题意:给一个数字序列,问你长度大于2的且相邻两个数的差的绝对值不大于d的情况对9901取余 思路:看了根本不会,都没想到是线段树的题目,弱哭~~~,看了大牛们的题解,算是知道怎么回事...
  • Dan__ge
  • Dan__ge
  • 2016年06月09日 11:03
  • 1991

HDU 3333 线段树+离线处理

点击打开链接 题意:问你给定区间内的不重复的数字的和,如1 1 1 3 4 ,区间1到2就是1,区间1到5就是8 思路:这种线段树只能离线来写,离线的方法是按照查询区间的右端点来排序,然后这道题目...
  • Dan__ge
  • Dan__ge
  • 2016年06月12日 21:03
  • 1703

最近公共祖先(LCA)算法实现过程 【Tarjan离线+倍增在线+RMQ】

最近公共祖先(LCA) 首先来介绍下最近公共祖先(LCA)的概念 百度上的解释:对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度...
  • my_sunshine26
  • my_sunshine26
  • 2017年05月24日 22:31
  • 1172

BZOJ4025: 二分图(线段树+并查集)

传送门题解: 每个边分给logn\log n个区间,之后从上往下做并查集即可。 注意按秩合并,这样才可以撤销操作。#include using namespace std; const int M...
  • qq_35649707
  • qq_35649707
  • 2017年12月17日 20:34
  • 38

DP斜率优化总结

DP斜率优化总结 寒假事情比较多,刚回来的一周都是聚会,外加自己不务正业了几天浪费了大半的时间,春节前后还是抽空学习了一下斜率优化DP。 理论基础见NOI2004年周源的论...
  • pi9nc
  • pi9nc
  • 2013年07月27日 21:45
  • 7593

hdu-4991(dp+线段树)

对于线段树有了更新的认识。 题意:从无序串中求长度为k的严格上升序列的个数。 设dp[ i ][ j ]为以位置i的数为结尾的长度为j的严格上升序列的个数。 则dp[ i ][ j ...
  • u014492306
  • u014492306
  • 2015年01月29日 21:46
  • 491

poj 3171 dp+线段树优化

声明一点:网上的解答 题目都没看清!!!!,害我整整2天改代码。。。。。                   首先给定M,E ,然后给出其它区间的范围  注意   M             ...
  • sky_zdk
  • sky_zdk
  • 2017年03月30日 12:24
  • 103

#bzoj3187#区间修改的RMQ问题(zkw线段树版)

区间修改的RMQ问题 时间限制: 1 Sec  内存限制: 128 MB 题目描述 给出N(1 ≤ N ≤ 50,000)个数的序列A,下标从1到N,每个元素值均不超过1000。有两...
  • its_elaine
  • its_elaine
  • 2017年03月11日 10:47
  • 384

POJ 3162 树形dp+线段树

Walking Race Time Limit: 10000MS   Memory Limit: 131072K Total Submissions: 2524   Accepted: 6...
  • u012358934
  • u012358934
  • 2014年02月11日 13:51
  • 741
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:poj 3419 Difference Is Beautiful (dp+二分+RMQ或者dp+离线线段树)
举报原因:
原因补充:

(最多只允许输入30个字)