主席树——求区间第k个不同的数字(向右密集hdu5919)
和向左密集比起来向右密集只需要进行小小的额修改,就是更新的时候从右往左更新。。
自己写的被卡死时间。不知道怎么回事,和网上博客的没啥区别。。
/*
给定一个n个数的序列a
每次询问区间[l,r],求出去重后区间中每个数的第一次出现的位置pi
pi构成一个新的升序,求这个新数组的中位数 要求强制在线,询问[l,r]根据上一个询问的答案进行加密,形成新的询问
t1=(l+ansi-1) % mod n + 1
t2=(r+ansi-1) % mod n + 1
l=min(t1,t2),r=max(t1,t2)
然后再进行询问即可 先求出a[i]在序列中上一次出现的位置pre[i]
从左往右进行一次扫描,用主席树来维护区间[1,i]的中不同数字的个数
询问[l,r]:
先求出区间出现的不同数字的个数k,具体操作见SPOJ D-QUERY
要求从左往右第k/2个数,很容易想到二分,在第r棵线段树上询问[mid,r]区间不同数字出现的个数,这样的复杂度是O(q*(logn)^2)
但这种做法是错的。。
出现这种情况是因为我们所有版本的线段树的点都是向后密集的,第i个棵线段树维护a[i]及之前的数最后出现的位置 所以只要每个版本的线段树中不同的数出现的位置能够向前密集,那么这个问题就转变成了求第k大的数
考虑如何将数据向前密集,即保存a[i]下一次出现的位置,扫到a[i]时将i+1,将下一次出现的位置-1即可
update:a[i]
所以从右往左更新主席树,nxt[i]-1,i+1
query:[l,r]
先在第l个版本的线段树上查询[1,r]区间的不同数字的个数l
在第l个版本的线段树上查询[1,r]范围内的第k/2大数的下标 可以发现这种主席树的查询其实退化成了线段树
*/
#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
#define INF 0x3f3f3f3f
struct Node{int lc,rc,sum;}t[maxn*];
int n,a[maxn],rt[maxn],size,nxt[maxn],pos[maxn];
int build(int l,int r){
int now=++size;
t[now].lc=t[now].rc=t[now].sum=;
if(l==r)return now;
int mid=l+r>>;
t[now].lc=build(l,mid);
t[now].rc=build(mid+,r);
return now;
}
int update(int last,int pos,int val,int l,int r){
int now=++size;
t[now]=t[last];t[now].sum+=val;
if(l==r)return now;
int mid=l+r>>;
if(pos<=mid)t[now].lc=update(t[last].lc,pos,val,l,mid);
else t[now].rc=update(t[last].rc,pos,val,mid+,r);
return now;
}
int query1(int rt,int L,int R,int l,int r){//查询区间[L,R]的和
if(L<=l && R>=r)return t[rt].sum;
int mid=l+r>>,res=;
if(L<=mid) res+=query1(t[rt].lc,L,R,l,mid);
if(R>mid)res+=query1(t[rt].rc,L,R,mid+,r);
return res;
}
int query2(int rt,int k,int l,int r){//查询线段树第k大的值
if(l==r)return l;
int mid=l+r>>;
if(k<=t[t[rt].lc].sum)return query2(t[rt].lc,k,l,mid);
else return query2(t[rt].rc,k-t[t[rt].lc].sum,mid+,r);
} int main(){
int T,q;cin>>T;
for(int tt=;tt<=T;tt++){
size=;memset(rt,,sizeof rt);
memset(nxt,0x3f,sizeof nxt);
memset(pos,0x3f,sizeof pos); scanf("%d%d",&n,&q);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
for(int i=n;i>=;i--){
nxt[i]=pos[a[i]];
pos[a[i]]=i;
}
rt[n+]=build(,n);
for(int i=n;i>=;i--){
if(nxt[i]==INF)rt[i]=update(rt[i+],i,,,n);//直接在点i增加1
else {
int tmp=update(rt[i+],nxt[i],-,,n);
rt[i]=update(tmp,i,,,n);
}
} printf("Case #%d:",tt);
int ans=,l,r;
while(q--){
scanf("%d%d",&l,&r);
int t1=(l+ans)%n+,t2=(r+ans)%n+;
l=min(t1,t2),r=max(t1,t2);
int k=query1(rt[l],,r,,n);
ans=query2(rt[l],k/+k%,,n);//求第k个数的下标
printf(" %d",ans);
}
puts("");
}
}
下面的是ac的。。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 222222
inline int read()
{
RG int x=,t=;RG char ch=getchar();
while((ch<''||ch>'')&&ch!='-')ch=getchar();
if(ch=='-')t=-,ch=getchar();
while(ch<=''&&ch>='')x=x*+ch-,ch=getchar();
return x*t;
}
int tot,rt[MAX];
struct Node
{
int ls,rs;
int v;
}t[MAX<<];
void Modify(int &x,int ff,int l,int r,int p,int w)
{
t[x=++tot]=t[ff];t[x].v+=w;
if(l==r)return;
int mid=(l+r)>>;
if(p<=mid)Modify(t[x].ls,t[ff].ls,l,mid,p,w);
else Modify(t[x].rs,t[ff].rs,mid+,r,p,w);
}
int Query(int r1,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return t[r1].v;
int mid=(l+r)>>,ret=;
if(L<=mid)ret+=Query(t[r1].ls,l,mid,L,R);
if(R>mid)ret+=Query(t[r1].rs,mid+,r,L,R);
return ret;
}
int Kth(int r1,int l,int r,int K)
{
if(l==r)return l;
int mid=(l+r)>>,s=t[t[r1].ls].v;
if(s>=K)return Kth(t[r1].ls,l,mid,K);
else return Kth(t[r1].rs,mid+,r,K-s);
}
int ans,n,a[MAX],m;
int lst[MAX],pos[MAX];
int main()
{
int T=read();
for(int TTT=;TTT<=T;++TTT)
{
printf("Case #%d:",TTT);
memset(rt,,sizeof(rt));
memset(t,,sizeof(t));
memset(lst,,sizeof(lst));
memset(pos,,sizeof(pos));
tot=ans=;
n=read();m=read();
for(int i=;i<=n;++i)a[i]=read();
for(int i=n;i;--i)
if(!pos[a[i]])Modify(rt[i],rt[i+],,n,i,),pos[a[i]]=i;
else
{
Modify(rt[i],rt[i+],,n,i,);
Modify(rt[i],rt[i],,n,pos[a[i]],-);
pos[a[i]]=i;
}
while(m--)
{
int L=(read()+ans)%n+,R=(read()+ans)%n+;
if(L>R)swap(L,R);
int S=Query(rt[L],,n,L,R);
ans=Kth(rt[L],,n,(S+)/);
printf(" %d",ans);
}
puts("");
}
return ;
}
主席树——求区间第k个不同的数字(向右密集hdu5919)的更多相关文章
- hdu4417 主席树求区间小于等于K
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 Problem Description Mario is world-famous plum ...
- 主席树--动态区间第k小
主席树--动态区间第\(k\)小 模板题在这里洛谷2617. 先对几个问题做一个总结: 阅读本文需要有主席树的基础,也就是通过区间kth的模板题. 静态整体kth: sort一下找第k小,时间复杂度\ ...
- poj 2104 主席树(区间第k大)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 44940 Accepted: 14946 Ca ...
- A - 低阶入门膜法 - K-th Number (主席树查询区间第k小)
题目链接:https://cn.vjudge.net/contest/284294#problem/A 题目大意:主席树查询区间第k小. 具体思路:主席树入门. AC代码: #include<i ...
- HDU 5919 - Sequence II (2016CCPC长春) 主席树 (区间第K小+区间不同值个数)
HDU 5919 题意: 动态处理一个序列的区间问题,对于一个给定序列,每次输入区间的左端点和右端点,输出这个区间中:每个数字第一次出现的位子留下, 输出这些位子中最中间的那个,就是(len+1)/2 ...
- [csu/coj 1080]划分树求区间前k大数和
题意:从某个区间内最多选择k个数,使得和最大 思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数 ...
- HDU 4417 Super Mario(主席树求区间内的区间查询+离散化)
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- 主席树——求区间[l,r]不同数字个数的模板(向左密集 D-query)
主席树的另一种用途,,(还有一种是求区间第k大,区间<=k的个数) 事实上:每个版本的主席树维护了每个值最后出现的位置 这种主席树不是以权值线段树为基础,而是以普通的线段树为下标的 /* 无修改 ...
- hdu 5919--Sequence II(主席树--求区间不同数个数+区间第k大)
题目链接 Problem Description Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2 ...
随机推荐
- C博客作业01--分支、顺序结构
1.本章学习总结 1.1 思维导图 1.2 本章学习体会及代码量学习体会 1.2.1 学习体会 在暑假已经有初步接触c语言,所以在学习c语言的开始会比较轻松,但仍然解题时候步骤太过于繁琐,简单的题目复 ...
- c语言利用读取命令行(多行读取)
#include<stdio.h> #include<stdlib.h> #include<string.h> int main() { FILE *fh = po ...
- [2019.03.16]使用DOM操作函数和CSS选择器来针对已有的HTML进行只凭JS的改动
刚入职的时候看到公司用的HTML日志生成工具附带的Panel,工具不够用,找个Fail还要找半天,于是自己琢磨着添砖加瓦.以前也是个半吊子前端工程师,现在可倒好,想要改页面却连页面生成的模板在哪里都不 ...
- [洛谷P1392] 取数
无法用复杂状态进行转移时改变计算方式:巧妙的整体考虑:压缩空间优化时间 传送门:$>here<$ 题意 给出一个n*m矩阵,从每一行选一个数加起来,可以得到一个和.易知总共会有$n^n$个 ...
- 题解:LOJ540游戏
题目描述 小L计划进行n场游戏,每场游戏使用一张地图,小 L 会同时使用三辆车在该地图上完成游戏. 小 L 的赛车有三辆,分别用大写字母 A.B.C 表示.地图是一张无向简单图(没有重边或自环),每次 ...
- 【php】php7新特性及其优化原理
php7.x版本系列相比之前的php的版本提交性能提高了不少,这里面其中的一些主要改变是性能提高的关键,主要有以下内容. 1.zval使用栈内存 在zend引擎和扩展中,经常要创建php变量,其底 ...
- 哈尔滨工程大学第十四届程序设计竞赛(同步赛)F 小帆帆走迷宫(dp)
题目描述 小帆帆被困在一个 NxN 的方格矩阵迷宫,每个格子中都有一个整数 A[i][j].小帆帆从迷宫起点(左上角)格子 A[1][1]开始走,每一步可以向右或向下移动,目标是移动到迷宫的出口右下角 ...
- Nginx安装及使用
安装 设置安装位置 切换到root下安装:CentOS: #su root Ubuntu: #sudo su 切换文件夹: #cd /usr/local/src/ 安装编译环境 ububtu平台编 ...
- js数组sort排序方法的算法
说明一下,ECMAScript没有定义使用哪种排序算法,各个浏览器的实现方式会有不同.火狐中使用的是归并排序,下面是Chrome的sort排序算法的实现. sort方法源码 DEFINE_METHOD ...
- Educational Codeforces Round 63 (Rated for Div. 2) D. Beautiful Array(动态规划.递推)
传送门 题意: 给你一个包含 n 个元素的序列 a[]: 定义序列 a[] 的 beauty 为序列 a[] 的连续区间的加和最大值,如果全为负数,则 beauty = 0: 例如: a[] = {1 ...