hdu 4638 离线+树状数组

来源:互联网 发布:vmware ubuntu 安装 编辑:程序博客网 时间:2024/05/29 14:04

题意

找到区间里有多少组连续数字串

分析:

(转)思路:显然,我们要使得value最大,就要尽量将连续的ID分在一组,所以问题转化为求一个区间中连续ID区间的个数。我们从左往右扫描,依次考虑右端点为i的询问,设dp[l]为区间[l,i]的连续区间个数,po[i]为i出现的位置,若还未出现,则为0,设我们当前考虑的右端点为a[i],首先我们假设a[i]不能和区间[1,i-1]中的任何一个数分到一组,则我们要将dp[1]到dp[i-1]全部加1,然后考虑po[a[i]+1]是否不为0,若不为0则说明a[i]-1已经在前面出现,则我们需要将dp[1]到dp[po[a[i]+1]]全部减一个1,因为a[i]可以和a[i]+1分为一组,则我们之前加的1是多余的。对于a[i]-1的情况同理。以上操作可以由线段树或者树状数组什么的实现,然后再将询问按照右端点从小到大排序,离线处理即可,以下是代码实现

#include<bits/stdc++.h>using namespace std;#define INF 0x3f3f3f3ftypedef long long LL;const int maxn=100005;int n,m,T;int c[maxn],pos[maxn],ans[maxn],a[maxn];struct node{    int l,r,id;}E[maxn];int cmp(node a,node b){    return a.r<b.r;}int lowbit(int x) //求最低位1的位置所表示的数{    return x&(-x);}void update(int p,int q)// 单点更新c[p] 加上q{                        //    (其中k为x二进制末尾0的个数)    while(p<=n)    {        c[p]+=q;        p+=lowbit(p);    }}int S(int x)  //S(i)表示的是的前i个数的和{    int sum=0;    while(x>0)    {        sum+=c[x];        x-=lowbit(x);    }    return sum;}int main(){    pos[0]=1e9;    scanf("%d",&T);    while(T--){        memset(c,0,sizeof(c));        scanf("%d%d",&n,&m);        pos[n+1]=1e9;        for(int i=1;i<=n;i++){            scanf("%d",&a[i]);            pos[a[i]]=i;        }        for(int i=1;i<=m;i++){            scanf("%d%d",&E[i].l,&E[i].r);            E[i].id=i;        }        sort(E+1,E+m+1,cmp);        int L=1;        int R;        for(int j=1;j<=m;j++){            R=E[j].r;            for(int i=L;i<=R;i++){                update(i,1);                if(pos[a[i]-1]<i){                    update(pos[a[i]-1],-1);                }                if(pos[a[i]+1]<i){                    update(pos[a[i]+1],-1);                }            }            ans[E[j].id]=S(E[j].r)-S(E[j].l-1);            L=R+1;        }        for(int i=1;i<=m;i++){            printf("%d\n",ans[i]);        }    }    return 0;}
0 0
原创粉丝点击