题目描述

  给你你个序列,每次求区间第\(k\)小的数。

  本题中,如果一个数在询问区间中出现了超过\(w\)次,那么就把这个数视为\(n\)。

  强制在线。

  \(n\leq 100000,a_i<n,w\leq n\)

题解

  考虑整体二分。

  先看看离线要怎么做。

  现在我们要计算每个数对每个区间的贡献。

  对于每个询问区间和每种数,让这个区间最右边\(w\)个数对这个询问的贡献为\(1\),第\(w+1\)个数对这个询问的贡献为\(-w\)。

  这样每个数的贡献就是二维平面上的一个矩形。可以用扫描线+线段树解决。

  时间复杂度:\(O(n\log n)\)

  但问题是强制在线。

  可以把这棵线段树可持久化。

  时间复杂度不变。

  总时间复杂度:\(O(n\log^2 n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#include<utility>
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
namespace sgt
{struct node{int ls,rs,v;};node a[50000010];int cnt;int insert(int p1,int l,int r,int v,int L,int R){int p=++cnt;a[p]=a[p1];if(l<=L&&r>=R){a[p].v+=v;return p;}int mid=(L+R)>>1;if(l<=mid)a[p].ls=insert(a[p].ls,l,r,v,L,mid);if(r>mid)a[p].rs=insert(a[p].rs,l,r,v,mid+1,R);return p;}int query(int p,int x,int L,int R){if(L==R)return a[p].v;int s=a[p].v;int mid=(L+R)>>1;if(x<=mid)s+=query(a[p].ls,x,L,mid);elses+=query(a[p].rs,x,mid+1,R);return s;}
}
struct change
{int x,y1,y2,k,w;change(){}change(int a,int c,int d,int e,int f){x=a;y1=c;y2=d;k=e;w=f;
//      printf("%d %d %d %d %d\n",x,y1,y2,k,w);}
};
int cmp(change a,change b)
{return a.x>b.x;
}
change c[1000010],c2[1000010];
int cnt;
int n,w,q,type;
int a[100010];
set<int> st[100010];
int rtcnt=0;
int ls[3000010];
int rs[3000010];
int crt;
vector<pii> d[3000010];
int build(int l,int r,int vl,int vr)
{if(vl==vr)return 0;int rr=++rtcnt;d[rr].push_back(pii());int now=0;int i;int vm=(vl+vr)>>1;int num=0;int cnt1=0;for(i=l;i<=r;i++){if(i!=l&&c[i].x!=c[i-1].x&&num){d[rr].push_back(pii(c[i-1].x,now));num=0;}if(c[i].k<=vm){now=sgt::insert(now,c[i].y1,c[i].y2,c[i].w,1,n);num++;cnt1++;}}if(num)d[rr].push_back(pii(c[r].x,now));int l1=l,r1=l+cnt1;for(i=l;i<=r;i++)if(c[i].k<=vm)c2[l1++]=c[i];elsec2[r1++]=c[i];for(i=l;i<=r;i++)c[i]=c2[i];ls[rr]=build(l,l+cnt1-1,vl,vm);rs[rr]=build(l+cnt1,r,vm+1,vr);return rr;
}
int get(vector<pii> &s,int x)
{if(s.size()==1)return 0;if(x>s[1].first)return 0;int l=1,r=s.size()-1;while(l<r){int mid=(l+r+1)>>1;if(x>s[mid].first)r=mid-1;elsel=mid;}return l;
}
int query(int rr,int l,int r,int k,int vl,int vr)
{if(vl==vr)return vl;int p=get(d[rr],l);int rt=d[rr][p].second;int s=sgt::query(rt,r,1,n);int vm=(vl+vr)>>1;if(k<=s)return query(ls[rr],l,r,k,vl,vm);elsereturn query(rs[rr],l,r,k-s,vm+1,vr);
}
int main()
{
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifscanf("%d%d%d%d",&n,&w,&q,&type);int x,i;for(i=1;i<=n;i++)scanf("%d",&a[i]);for(i=n;i>=1;i--){x=a[i];st[x].insert(i);int ed2=n;if(st[x].size()>=w+1){int ed=n;if(st[x].size()>=w+2){set<int>::iterator p=st[x].end();p--;ed=*p-1;st[x].erase(p);}set<int>::iterator p=st[x].end();p--;c[++cnt]=change(i,*p,ed,x,-w);ed2=*p-1;}c[++cnt]=change(i,i,ed2,x,1);}sort(c+1,c+cnt+1,cmp);int crt=build(1,cnt,0,n);int l,r,k;int last=0;for(i=1;i<=q;i++){scanf("%d%d%d",&l,&r,&k);if(type){l^=last;r^=last;k^=last;}last=query(crt,l,r,k,0,n);printf("%d\n",last);}return 0;
}

转载于:https://www.cnblogs.com/ywwyww/p/8513541.html

【XSY2720】区间第k小 整体二分 可持久化线段树相关推荐

  1. 经典题:poj2104-区间第k小 整体二分学习

    写在前面 区间第k小 可以说是一个很经典的数据结构题了,这道题有很多种解法比如莫队离线.主席树.整体二分等等. 之前用莫队和主席树写过这道题,今天来学习一个以前不会的算法--整体二分. 因为最近遇到一 ...

  2. 【整体二分】区间第k小(金牌导航 整体二分-1)

    区间第k小 金牌导航 整体二分-1 题目大意 给出一个序列,有若干查询,每次查询给出l,r,k,让你求l~r这个区间的第k大 输入样例 7 3 1 5 2 6 3 7 4 2 5 3 4 4 1 1 ...

  3. The UVALIVE 7716 二维区间第k小

    The UVALIVE 7716 二维区间第k小 /** 题意:给一个n * n的矩阵,有q个查询每次查询r,c,s,k表示已(r,c)为右上角 大小为s的正方形中 第k小的元素n <= 250 ...

  4. P3332 [ZJOI2013]K大数查询【整体二分】或【树套树】

    传送门 给定一个长度为NNN的可重集合 支持修改,离线 求区间可重集合的并集第K大 这里介绍两种方法[树套树]和 [整体二分] 这里还有个单点修改,有点类似的 P2617 Dynamic Rankin ...

  5. 动态区间第k小:树状数组套权值线段树

    所谓树状数组套权值线段树,就是在树状树组上套权值线段树 (逃) 解析 如何解决静态区间第k小? 使用主席树就ok啦 辣么如何解决动态区间第k小嘞- 我们想想主席树为啥不能解决动态区间第k小 因为如果改 ...

  6. 【代码源 Div1 - 108】#464. 数数(主席树,区间比k小的数的个数)HDU4417

    problem solution 主席树查询区间比k小的数的个数 建树之后直接在目标区间的主席树内将 H 作为挡板递归计数. #include<bits/stdc++.h> using n ...

  7. P3834 【模板】可持久化线段树 2(整体二分做法)

    P3834 [模板]可持久化线段树 2(主席树) 我们详细讲讲这个整体二分如何求区间第k小 我们都知道二分可以求出区间里某个想要的值,如果有很多询问,我们对每个询问都进行二分,复杂度就是O(QNlog ...

  8. SPOJ-COT-Count on a tree(树上路径第K小,可持久化线段树)

    题意: 求树上A,B两点路径上第K小的数 分析: 同样是可持久化线段树,只是这一次我们用它来维护树上的信息. 我们之前已经知道,可持久化线段树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表 ...

  9. 【BZOJ4504】K个串 可持久化线段树+堆

    [BZOJ4504]K个串 Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计 ...

最新文章

  1. [公告]欢迎您加入WF技术研究团队
  2. 【推荐】一下令人惊艳的的网站,绝对会让你爱上历史
  3. python小细节之else
  4. 《leetcode》valid-sudoku
  5. HDLBits答案(21)_Verilog有限状态机(8)
  6. python3闭包通俗解释_Python|闭包、装饰器,简单的实例,通俗的理解
  7. asp.net C# 计算运算耗时时间
  8. 程序员项目_您如何让程序员加入您的项目?
  9. 作为前端Web开发者,这12条基本命令不可不会
  10. AWS--EC2基本概念
  11. codevs 1683 车厢重组
  12. Activity/Fragment最强生命周期总结
  13. 上位机和下位机计算机联锁,上位机下位机各是什么意思?上位机下位机介绍
  14. Java实现第九届蓝桥杯分数
  15. vue:antV G2在vue中的使用(阿里图表,类似echarts)
  16. 百度地图 创建应用
  17. html打开网页过场动画_一款谷歌(Google)打造的广告网页设计制作软件
  18. ipad查看电脑中的文件
  19. TweenMax介绍
  20. Jupyter Notebooks学习分享

热门文章

  1. axure元件库 文件上传_手把手教你打造一套属于产品经理自己的元件库
  2. erosa mysql_MySQL协议和canal实现
  3. php mysql导出csv文件_详解PHP导入导出CSV文件
  4. 使用react实现select_使用 Hooks 优化 React 组件
  5. 为什么C语言函数不能返回数组,却可以返回结构体
  6. python程序、画一个笑脸_如何使用canvas画一个微笑的表情(代码示例)
  7. c语言输出星期几的英语表达,C语言程序设计: 输入年月日 然后输出是星期几...
  8. 浙江金融职业学院计算机一级,浙江金融职业学院全景-360度,720度,高清全景地图-expoon网展...
  9. 光纤收发器常见六大故障,三分钟全部搞定
  10. 【渝粤教育】国家开放大学2018年秋季 0239-21T电子商务物流管理 参考试题