HDU 4595 Similar Number (主席树)

解析:首先,求出对于每一个位置i,以第i个元素结尾的相似序列的最大长度和最小长度,用lb[i]和rb[i]记录对应的位置,形成一个三元组(i,lb[i],rb[i])。

这个可以通过递推在O(n)内求出,然后将三元组映射成二维平面的线段(i是纵坐标,lb[i],rb[i]是左右端点的横坐标)。

对于[l,r]的查询,就是对纵坐标[1,r]的所有线段中位于[l,r]的和。

用主席树就可以实现。

[code]:

#include<cstdio>
#include<cstring>
#include<algorithm>

#define lson l,mid
#define rson mid+1,r
using namespace std;
typedef long long LL;
const int maxn = 1e5+5;
const int MX = 200*maxn;

int n,m,a[maxn],bit[20],top;
int lb[maxn],rb[maxn],pr[maxn];
int mc[maxn],hah;
int RT[maxn],Left[MX],Right[MX],D[MX],tot;
LL C[MX];

void init(){
    hah = tot = 0;
}
void copy(int k,int p){
    C[k] = C[p];D[k] = D[p];
    Left[k] = Left[p];Right[k] = Right[p];
}
void push_up(int root){
    C[root] = C[Left[root]]+C[Right[root]];
}
void push_down(int l,int r,int root){
    if(l == r||D[root]==0) return;
    int lrt,rrt,mid;
    mid = (l+r)>>1;
    lrt = tot++;rrt = tot++;
    copy(lrt,Left[root]);copy(rrt,Right[root]);
    Left[root] = lrt;Right[root] = rrt;
    D[lrt] += D[root];
    D[rrt] += D[root];
    C[lrt] += 1LL*(mid-l+1LL)*D[root];
    C[rrt] += 1LL*(r-mid)*D[root];
    D[root] = 0;
}
int build(int l,int r){
    int root = tot++;
    C[root] = 0;D[root] = 0;
    if(l == r) return root;
    int mid = (l+r)>>1;
    Left[root] = build(lson);
    Right[root] = build(rson);
    return root;
}
int update(int a,int b,int l,int r,int root){
    push_down(l,r,root);
    int newroot = tot++;
    copy(newroot,root);
    if(a<=l&&r<=b){
        C[newroot] = C[root] + (r-l+1);
        D[newroot] = 1;
        return newroot;
    }
    int mid = (l+r)>>1;
    if(b<=mid){
        Left[newroot] = update(a,b,lson,Left[root]);
    }else if(a>mid){
        Right[newroot] = update(a,b,rson,Right[root]);
    }else{
        Left[newroot] = update(a,b,lson,Left[root]);
        Right[newroot] = update(a,b,rson,Right[root]);
    }
    push_up(newroot);
    return newroot;
}
LL query(int a,int b,int l,int r,int root){
    push_down(l,r,root);
    if(a <= l&&r <= b) return C[root];
    if(l > b||r < a) return 0;
    int mid = (l+r)>>1;
    return query(a,b,lson,Left[root])+query(a,b,rson,Right[root]);
}
void preprocess(){
    int i,j;
    memset(pr,-1,(hah+1)*sizeof(int));
    lb[1] = 1;rb[1] = 0;
    pr[a[1]] = 1;
    RT[1] = RT[0] = build(1,n);
    for(i = 2;i <= n;i++){
        if(pr[a[i]]==-1){
            rb[i] = rb[i-1];
            lb[i] = lb[i-1];
        }else{
            if(pr[a[i]]>=rb[i-1]){
                rb[i] = pr[a[i]];
                lb[i] = rb[i-1]+1;
            }else{
                rb[i] = rb[i-1];
                lb[i] = max(lb[i-1],pr[a[i]]+1);
            }
        }
        pr[a[i]] = i;
        if(rb[i]){
            RT[i] = update(lb[i],rb[i],1,n,RT[i-1]);
        }else RT[i] = RT[i-1];
    }
}

int main(){
    int i,j;
    while(~scanf("%d%d",&n,&m)){
        init();
        for(i = 1;i <= n;i++){
            scanf("%d",&a[i]);
            top = 0;
            if(a[i]) for(;a[i];a[i]/=10) bit[top++]=a[i]%10;
            else bit[top++]=0;
            sort(bit,bit+top);
            for(j = top-1;j>=0;j--) a[i] = a[i]*10+bit[j];
            mc[hah++] = a[i];
        }
        sort(mc,mc+hah);
        hah = unique(mc,mc+hah)-mc;
        for(i = 1;i <= n;i++){
            a[i] = lower_bound(mc,mc+hah,a[i])-mc+1;
        }
        preprocess();
        LL l,r,tmp = 0;
        while(m--){
            scanf("%I64d%I64d",&l,&r);
            l += tmp;
            r -= tmp;
            tmp = query((int)l,(int)r,1,n,RT[r]);//-query(l,r,1,n,RT[l-1]);
            printf("%I64d\n",tmp);
        }
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值