HDU - 5919 Sequence II——主席树+区间种类++逆序建树
【题目描述】
HDU - 5919 Sequence II
【题目分析】
题目给定一个数组,每次查询一个区间,找出区间内不同数字的个数x,然后输出按出现顺序第x/2向上取整个数字的位置。
- 按照要求,我们首先需要能够找出给定区间不同的数字个数。
首先,我们分析一个简单一些的问题:对于右端点固定的区间,如何计算不同左区间内不同数字的个数。
我们不妨用一个数组记录cntcntcnt哪些位置出现了一个不同的数字,用sumsumsum数组进行维护cnt[1..l]cnt[1..l]cnt[1..l]的和(可以用线段树或者树状数组),那么对于区间[l,r][l,r][l,r]内不同数字的个数就是sum[r]−sum[l−1]sum[r]-sum[l-1]sum[r]−sum[l−1]。
在从前往后进行添加的过程中,如果该数字在前面已经出现,就将前面的标记消除,在后面的位置进行标记,也就是说尽可能将标记后放。例如对于数组1,2,2,3,5,11,2,2,3,5,11,2,2,3,5,1维护以后的cntcntcnt数组就是0,0,1,1,1,10,0,1,1,1,10,0,1,1,1,1,这样做的原因是我们假设的是右端点固定,对于重复的元素,在后面如果出现过前面就没有必要标记。
如果询问是离线的,我们大可以先将询问保存下来,然后从前往后加入数据的过程中不断将对应的询问答案保存(对应是指右端点相同),最后输出就可以了。
可是这个问题是强制在线的,所以我们必须使用主席树进行可持久化。可是这种可持久化和以前的主席树运用不同,因为在添加的过程中会将前面的标记消除,所以不同根节点的主席树不在拥有可以互相加减的能力(加减的结果不再有意义)。然而在我们这个问题里面我们是不需要进行加减的。 - 不同于求区间第K大的时候我们的主席树维护的是值区间,即值在区间内的个数,这里根节点的1..n1..n1..n指的是数据范围aiaiai的最大值。在这里我们的根节点的1..n1..n1..n的nnn指的是数据的个数,就是题目中的nnn,标记的是该位置上出现了一个之前没有出现过的数字。 因此对于每次询问,我们访问的版本里保存的就是实际的数组,直接计数就可以。而区间第K大就需要减去之前的版本才是该区间内的数的个数。
- 题目要求的是数据第一次出现的位置,可是按照上面的想法进行建树的话我们保存的是当前区间[1,i][1,i][1,i]数据最后一次出现的位置。很自然,我们应该进行逆序建树,这样的话我们保存的就是[i,n][i,n][i,n]区间内数据第一次出现的位置,对于需要查询的区间[l,r][l,r][l,r],我们访问第lll个版本的主席树,就满足题目要求啦。
求出数字的个数后我们再除以2向上取整就是题目要求的k,然后在找出对应的位置,这里类似区间第K大
【参考文献】
大佬博客1
大佬博客2
【AC代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<climits>
#include<string>
#include<cmath>
#include<cstdlib>using namespace std;const int MAXN=200005;
int a[MAXN];
int n,m;
struct node
{int ls,rs,cnt;
}tree[MAXN*40];
int root[MAXN*40];
int b[MAXN];
int tot;void Insert(int &now,int pre,int x,int l,int r,int add)
{int tmp=now; now=++tot;tree[now]=tmp?tree[tmp]:tree[pre];tree[now].cnt+=add;if(l==r) return;int mid=(l+r)>>1;if(x<=mid) Insert(tree[now].ls,tree[pre].ls,x,l,mid,add);else Insert(tree[now].rs,tree[pre].rs,x,mid+1,r,add);
}int GetSum(int k,int l,int r,int L,int R)
{if(l>=L && r<=R) return tree[k].cnt;int ret=0; int mid=(l+r)>>1;if(L<=mid) ret+=GetSum(tree[k].ls,l,mid,L,R);if(R>mid) ret+=GetSum(tree[k].rs,mid+1,r,L,R);return ret;
}int query(int k,int l,int r,int x)
{if(l==r) return l;int mid=(l+r)>>1;int tmp=tree[tree[k].ls].cnt;if(x<=tmp) query(tree[k].ls,l,mid,x);else query(tree[k].rs,mid+1,r,x-tmp);
}int main()
{int T,ans,l,r,tmp,sum;scanf("%d",&T);for(int Case=1;Case<=T;Case++){scanf("%d%d",&n,&m);memset(tree,0,sizeof(tree));memset(a,0,sizeof(a));memset(b,0,sizeof(b));memset(root,0,sizeof(root));tot=0;for(int i=1;i<=n;i++){scanf("%d",&a[i]);}for(int i=n;i>0;i--){if(b[a[i]]) Insert(root[i],root[i+1],b[a[i]],1,n,-1);Insert(root[i],root[i+1],i,1,n,1);b[a[i]]=i;}ans=0;printf("Case #%d:",Case);//测试 //printf("\n");for(int i=0;i<m;i++){scanf("%d%d",&l,&r);l=(l+ans)%n+1; r=(r+ans)%n+1;if(l>r) tmp=l,l=r,r=tmp;//printf("test: l=%d r=%d\n",l,r);sum=GetSum(root[l],1,n,l,r);//printf("test: sum=%d\n",sum);sum=(sum+1)/2;//printf("test: sum=%d\n",sum);ans=query(root[l],1,n,sum);printf(" %d",ans);}printf("\n");}return 0;
}
HDU - 5919 Sequence II——主席树+区间种类++逆序建树相关推荐
- HDU 5919 Sequence II 主席树
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5919 Sequence II Time Limit: 9000/4500 MS (Java/Othe ...
- HDU - 5919 Sequence II(主席树+思维)
题目链接:点击查看 题目大意:给出一个长度为 n 的数列 a ,再给出 m 次询问,每次询问给出一个区间 [ l , r ] ,问区间 [ l , r ] 内首次出现的数字的位置的中位数 题目分析:题 ...
- HDU - 4348To the moon——主席树+区间修改
HDU - 4348To the moon [题目描述] [题目分析] 题目中说明每次更新后时间都会加1,而且还会需要查询以前的区间,还会需要返回以前的时间,所以是很裸的主席树.区间查询的话我们同样需 ...
- HDU - 5919 Sequence II
题意: 给定长度为n的序列和q次询问.每次询问给出一个区间(L,R),求出区间内每个数第一次出现位置的中位数,强制在线. 题解: 用主席树从右向左的插入点.对于当前点i,如果a[i]出现过,则把原位置 ...
- Hdu-5919 Sequence II(主席树在线求区间不同数)
Description Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,an There a ...
- HDU - 3397 Sequence operation(线段树+区间合并)
题目链接:点击查看 题目大意:给定一个初始的数列,然后依次进行m次操作: 0 a b:将闭区间[a,b]内的点都变为0 1 a b:将闭区间[a,b]内的点都变为1 2 a b:将闭区间[a,b]内的 ...
- hdu 3397 Sequence operation(线段树,lazy,区间合并)
hdu 3397 Sequence operation 线段树lazy和区间合并结合的一个题,相当于几个题集中到一起嘛,分开想就好了 0,1,2操作都要lazy,2的异或操作找到每一只含1或只含0的区 ...
- HDU 4348 To the moon(主席树区间修改)
题意 给你一个区间,支持如下操作: 在一段区间内加上一个值,并生成一个历史版本 查询某个版本下一段区间内的和 回到一个历史版本上并舍弃之后的版本 做法 这就是主席树区间修改裸题啦QwQ 上一篇博客我讲 ...
- HDU - 4348 To the moon(主席树区间更新-标记永久化)
题目链接:点击查看 题目大意:给出一个初始时长度为 n 的序列,有 m 次操作,每种操作分为下列四种类型: C l r d:新建一个继承了前一个版本的数组,并将区间 [ l , r ] 内的数字都加上 ...
最新文章
- 中国雪糕红黑榜,谁才是Top 1
- SAP MM PIR里的Lower Limit Upper Limit
- hdu 4751(dfs染色)
- JUC并发编程十 并发架构--Unsafe
- centos磁盘空间满查询和移动命令小记
- python图像识别车票_是程序员就用Python查12306的票
- TensorFlow和ML前5名的课程
- python一图带你精通time类型转换
- React中的this指向问题
- 波波老师: 解决微服务的数据一致性分发问题?
- 函数yield报错ValueError: too many values to unpack (expected 2)
- oracle11g调整表空间和临时表空间大小
- 有以下程序C语言a b cdef,[工学]全国计算机二级笔试基础部分和C语言程序设计.doc...
- 暑假集训 div1 B Derangement 交换数字 思维死角
- 向数据库插入数据时出现乱码 --设置连接数据库的编码
- MAC 开发环境搭建及工具
- matlab激光扩束总结,zemax笔记14——激光扩束系统的设计
- 【WEB搜索技术】课程学习大纲与学习感悟
- hyperf 热重启
- kali虚拟机安装提示安装系统步骤失败
热门文章
- PHP中unset,array_splice删除数组中元素的区别
- 万网与阿里巴巴业务关系图解
- linux mint 18.3 内核,Linux Mint 18.3 “Sylvia” Cinnamon正式发布上线
- java scrollpane 设置透明_java swing 之 JScrollPane(滚动面板)的使用
- oppo 手机侧滑快捷菜单_OPPO刚秀出卷轴屏手机,就被打了一记响亮的“耳光”
- python利用opencv去除图片logo_利用python和opencv批量去掉图片黑边
- python pyplot中axis_Python Pyplot xaxis未显示在图形上
- 哈师大计算机等级考试,哈尔滨师范大学教务处
- C语言程序设计孙家啸第一版,广东年月自考各专业课程使用教材.doc
- react 判断图片是否加载完成_React中型项目的优化实践