POJ 3368 Frequent values(线段树区间合并)

传送门:http://poj.org/problem?id=3368
题意:输入一个n个元素排好序的序列,然后输入q个查询。每次查询一个区间,输出这个区间内出现最多次数的数字的次数,但是因为序列已经是排序好的,所以相等的数字一定是相邻的。所以用线段树,记录每个区间的最左边的数字,和最右边的数字,左边的连续长度,右边的连续长度,最长的总长度。然后查询的时候区间合并一下就可以搞了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <ctime>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
#define PB push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define calm (l+r)>>1
const int INF=1e9+7;

const int maxn=100000;
int ll[maxn<<2],rr[maxn<<2],llen[maxn<<2],rlen[maxn<<2],sum[maxn<<2];
int n,m;
inline void pushup(int rt){
    sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
    ll[rt]=ll[rt<<1];   rr[rt]=rr[rt<<1|1];
    llen[rt]=llen[rt<<1];   rlen[rt]=rlen[rt<<1|1];
    if(ll[rt<<1]==rr[rt<<1]){
        if(rr[rt<<1]==ll[rt<<1|1]){
            llen[rt]=llen[rt<<1]+llen[rt<<1|1];
        }
    }
    if(ll[rt<<1|1]==rr[rt<<1|1]){
        if(ll[rt<<1|1]==rr[rt<<1]){
            rlen[rt]=rlen[rt<<1|1]+rlen[rt<<1];
        }
    }
    if(rr[rt<<1]==ll[rt<<1|1]){
        sum[rt]=max(sum[rt],rlen[rt<<1]+llen[rt<<1|1]);
    }
    sum[rt]=max(sum[rt],max(llen[rt],rlen[rt]));
}
void build(int l,int r,int rt){
    ll[rt]=rr[rt]=llen[rt]=rlen[rt]=sum[rt]=0;
    if(l==r){
        int x;scanf("%d",&x);
        ll[rt]=rr[rt]=x;
        llen[rt]=rlen[rt]=sum[rt]=1;
        return;
    }
    int m=calm;
    build(lson);build(rson);
    pushup(rt);
}
struct node{
    int ll,rr,llen,rlen,sum;
    node(){}
    node(int ll,int rr,int llen,int rlen,int sum):ll(ll),rr(rr),llen(llen),rlen(rlen),sum(sum){}
};
node merge(node left,node right){
    node ans;
    ans.sum=max(left.sum,right.sum);
    ans.ll=left.ll; ans.rr=right.rr;
    ans.llen=left.llen; ans.rlen=right.rlen;
    if(left.ll==left.rr){
        if(left.rr==right.ll){
            ans.llen=left.llen+right.llen;
        }
    }
    if(right.ll==right.rr){
        if(left.rr==right.ll){
            ans.rlen=left.rlen+right.rlen;
        }
    }
    if(left.rr==right.ll){
        ans.sum=max(ans.sum,left.rlen+right.llen);
    }
    ans.sum=max(ans.sum,max(ans.llen,ans.rlen));
    return ans;
}
node query(int L,int R,int l,int r,int rt){
    if(L<=l&&r<=R){
        return node(ll[rt],rr[rt],llen[rt],rlen[rt],sum[rt]);
    }
    int m=calm;
    if(R<=m)return query(L,R,lson);
    if(L>m)return query(L,R,rson);
    return merge(query(L,R,lson),query(L,R,rson));
}
int main(){
    //freopen("input.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        if(n==0)break;
        scanf("%d",&m);
        build(1,n,1);
        while(m--){
            int L,R;scanf("%d%d",&L,&R);
            printf("%d\n",query(L,R,1,n,1).sum);
        }
    }
    //printf("[Run in %.1fs]\n",(double)clock()/CLOCKS_PER_SEC);
    return 0;
}

你可能感兴趣的:(POJ 3368 Frequent values(线段树区间合并))