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

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 的,还有些 i dp[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;
}

你可能感兴趣的:(poj 3419 Difference Is Beautiful (dp+二分+RMQ或者dp+离线线段树))