HDU 5919 Sequence II

来源:互联网 发布:北京科技大学网络登录 编辑:程序博客网 时间:2024/05/28 15:29

HDU 5919 Sequence II

主席树处理序列问题

题意

给你n(n2105)个数,每个数的大小0<Ai2105。再给你m(m2105)个询问。对于每个询问输入l,r,表示Al…Ar这个区间我们得到每个数第一次出现的位置下标的排列,假设这个区间有k个不同的数,我们得到的排列是p1<p2<p3<...<pk,叫你求第(k+1)/2这个数是多少?

思路

比较经典的主席树维护区间种类问题的变形。

相同元素只取最左侧位置,所以对序列a,从a[n]到a[1]建立主席树,插入新元素到主席树中时取消相同元素的贡献,只保留最左侧元素。
查询[l, r]的时候,查询第l个版本的主席树就好,复杂度O(nlogn)。

这里需要注意一下(其实是主席树基本用法需要注意的东西),当对某版本进行多次单点更新的时候,每次都需要新增一条路径,必须保证不对以往的版本造成影响。

代码

#include<bits/stdc++.h>typedef long long LL;const int MAXN=200007;using namespace std;int cnt,root[MAXN],a[MAXN];struct Node{int l, r, sum;}T[MAXN*40];void update(int l,int r,int &x,int y,int pos,int c){    x=++cnt;    T[x]=T[y];T[x].sum+=c;    if(l==r) return;    int mid=(l+r)>>1;    if(pos<=mid) update(l,mid,T[x].l,T[y].l,pos,c);    else update(mid+1,r,T[x].r,T[y].r,pos,c);}int query(int L,int R,int l,int r,int x){    if(L<=l&&r<=R) return T[x].sum;    int mid=(l+r)>>1;    int ans=0;    if(L<=mid) ans+=query(L,R,l,mid,T[x].l);    if(mid<R) ans+=query(L,R,mid+1,r,T[x].r);    return ans;}int find_Kth(int l,int r,int x,int k){    if(l==r) return l;    int mid=(l+r)>>1;    int sum=T[T[x].l].sum;    if(sum>=k) return find_Kth(l,mid,T[x].l,k);    else return find_Kth(mid+1,r,T[x].r,k-sum);}int pre[MAXN];int result[MAXN];int main(){    int t;scanf("%d",&t);int cas=0;    while(t--)    {        int n,m;        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++)            scanf("%d",&a[i]);        memset(pre,0,sizeof(pre));        memset(root,0,sizeof(root));        memset(T,0,sizeof(T));        cnt=0;        for(int i=n;i>=1;i--)        {            update(1,n,root[i],root[i+1],i,1);            if(pre[a[i]]) update(1,n,root[i],root[i],pre[a[i]],-1);            pre[a[i]]=i;        }        result[0]=0;        for(int i=1;i<=m;i++)        {            int ll,rr;scanf("%d%d",&ll,&rr);            int l=min((ll+result[i-1])%n+1,(rr+result[i-1])%n+1);            int r=max((ll+result[i-1])%n+1,(rr+result[i-1])%n+1);            //printf("l:%d,r:%d\n",l,r);            int tmp=query(l,r,1,n,root[l]);            //printf("%d\n",tmp);            tmp=(tmp+1)/2;            result[i]=find_Kth(1,n,root[l],tmp);        }        printf("Case #%d:",++cas);        for(int i=1;i<=m;i++)        {            printf(" %d",result[i]);        }        printf("\n");    }}
原创粉丝点击