【莫队算法】【权值分块】poj2104 K-th Number / poj2761 Feed the dogs

先用莫队算法保证在询问之间转移的复杂度,每次转移都需要进行O(sqrt(m))次插入和删除,权值分块的插入/删除是O(1)的。

然后询问的时候用权值分块查询区间k小值,每次是O(sqrt(n))的。

所以总共的复杂度是O(m*(sqrt(n)+sqrt(m)))的。

常数极小。

别的按权值维护的数据结构无法做到O(1)地插入删除。

poj2104 的输出优化 别忘了处理负数。

完爆主席树,这份代码目前在 poj2761 上 Rank1

Rank Run ID User Memory Time Language Code Length Submit Time
1 13702017(2) lizitong 4056K 579MS G++ 2455B 2014-12-10 13:00:22
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int Num,CH[12],f,c;
inline void R(int &x){
    c=0;f=1;
    for(;c<‘0‘||c>‘9‘;c=getchar())if(c==‘-‘)f=-1;
    for(x=0;c>=‘0‘&&c<=‘9‘;c=getchar())(x*=10)+=(c-‘0‘);
    x*=f;
}
inline void P(int x){
    if(x<10)putchar(x+‘0‘);
    else{P(x/10);putchar(x%10+‘0‘);}
}
struct Point{int v,p;}t[100001];
struct Ask{int l,r,k,p;}Q[5001];
int n,m,a[100001],ma[100001],en,num[100001],num2[100001];
int l[330],r[330],sumv[330],b[100001],sum=1,anss[5001];
bool operator < (const Point &a,const Point &b){return a.v<b.v;}
bool operator < (const Ask &a,const Ask &b)
{return num2[a.l]!=num2[b.l] ? num2[a.l]<num2[b.l] : a.r<b.r;}
void Mo_Make_Block()
{
	int sum=1,sz=sqrt(n); if(!sz) sz=1;
	for(;sum*sz<n;++sum)
	  {
	  	int r=sum*sz;
	  	for(int i=(sum-1)*sz+1;i<=r;++i) num2[i]=sum;
	  }
	for(int i=(sum-1)*sz+1;i<=n;++i) num2[i]=sum;
}
void Val_Make_Block()
{
	int sz=sqrt(en); if(!sz) sz=1;
	for(;sum*sz<en;++sum)
	  {
	  	l[sum]=r[sum-1]+1; r[sum]=sum*sz;
	  	for(int i=l[sum];i<=r[sum];++i) num[i]=sum;
	  }
	l[sum]=r[sum-1]+1; r[sum]=en;
	for(int i=l[sum];i<=r[sum];++i) num[i]=sum;
}
void Insert(const int &x){++b[x]; ++sumv[num[x]];}
void Delete(const int &x){--b[x]; --sumv[num[x]];}
int Kth(const int &x)
{
    int cnt=0;
    for(int i=1;;i++)
      {
        cnt+=sumv[i];
        if(cnt>=x)
          {
            cnt-=sumv[i];
            for(int j=l[i];;j++)
            {cnt+=b[j]; if(cnt>=x) return j;}
          }
      }
}
int main()
{
	R(n); R(m);
	for(int i=1;i<=n;++i) {R(t[i].v); t[i].p=i;}
	sort(t+1,t+n+1);
	ma[a[t[1].p]=++en]=t[1].v;
	for(int i=2;i<=n;++i)
	  {
	  	if(t[i].v!=t[i-1].v) ++en;
	  	ma[a[t[i].p]=en]=t[i].v;
	  }
	Val_Make_Block();
	for(int i=1;i<=m;++i)
	  {
	  	R(Q[i].l); R(Q[i].r); R(Q[i].k);
	  	Q[i].p=i;
	  }
	Mo_Make_Block();
	sort(Q+1,Q+m+1);
	for(int i=Q[1].l;i<=Q[1].r;++i) Insert(a[i]);
	anss[Q[1].p]=ma[Kth(Q[1].k)];
	for(int i=2;i<=m;++i)
      {
        if(Q[i].l<Q[i-1].l) for(int j=Q[i-1].l-1;j>=Q[i].l;--j) Insert(a[j]);
        else for(int j=Q[i-1].l;j<Q[i].l;++j) Delete(a[j]);
        if(Q[i].r<Q[i-1].r) for(int j=Q[i-1].r;j>Q[i].r;--j) Delete(a[j]);
        else for(int j=Q[i-1].r+1;j<=Q[i].r;++j) Insert(a[j]);
        anss[Q[i].p]=ma[Kth(Q[i].k)];
      }
    for(int i=1;i<=m;++i) P(anss[i]),puts("");
	return 0;
}
时间: 2024-08-10 21:16:56

【莫队算法】【权值分块】poj2104 K-th Number / poj2761 Feed the dogs的相关文章

Luogu 1494 - 小Z的袜子 - [莫队算法模板题][分块]

题目链接:https://www.luogu.org/problemnew/show/P1494 题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬. 你的任务便是告诉小Z,他有多大的概率抽到两只颜

(莫队算法)CodeForces - 617E XOR and Favorite Number

题意: 长度为n的数列,m次询问,还有一个k.每次询问询问询问从数列的L到R内有多少个连续子序列异或起来等于k. 分析: 因为事先知道这题可以用莫队写,就正好用这题练习莫队. 预处理每个前缀异或和. 然后莫队按分块排序后,不断更新,用一个数组cnt[]记录当前L到R前缀和的数量. R向右拉,新增的数量就是cnt[pre^k],pre表示当前这个R位置的前缀异或和,然后更新一下cnt. 其他的也类似. 算是一个比较好的入门题. 代码: 1 #include <cstdio> 2 #include

【莫队算法】【权值分块】bzoj3920 Yuuna的礼物

[算法一] 暴力. 可以通过第0.1号测试点. 预计得分:20分. [算法二] 经典问题:区间众数,数据范围也不是很大,因此我们可以: ①分块,离散化,预处理出: <1>前i块中x出现的次数(差分): <2>第i块到第j块中的众数是谁,出现了多少次. 询问的时候,对于整块的部分直接获得答案:对于零散的部分,暴力统计每个数出现 的次数,加上差分的结果,尝试更新ans. 时间复杂度O(m*sqrt(n)), 空间复杂度O(n*sqrt(n)). ②考虑离线,莫队算法,转移的时候使用数据

【莫队算法】【权值分块】bzoj2223 [Coci 2009]PATULJCI

不带修改主席树裸题<=>莫队+权值分块裸题. 复杂度O(m*sqrt(n)). P.S.题目描述坑爹,第二个数是权值的范围. #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define N 300001 #define M 10001 int f,c; inline void R(int &x){ c=0;f=1; for(;c<'0'||c

【DFS序列】【莫队算法】【权值分块】bzoj2809 [Apio2012]dispatching

题意:在树中找到一个点i,并且找到这个点子树中的一些点组成一个集合,使得集合中的所有点的c之和不超过M,且Li*集合中元素个数和最大 首先,我们将树处理出dfs序,将子树询问转化成区间询问. 然后我们发现,对于单一节点来说,“使得集合中的所有点的c之和不超过M,且Li*集合中元素个数和最大”可以贪心地搞,即优先选择c较小的点.(<--这正是主席树/权值线段树/权值分块的工作) 但是我们需要枚举所有节点,从他们中选一个最大的. 既然有dfs序了,那么就是无修改的区间询问咯.(<--莫队的工作)

【莫队算法】【权值分块】bzoj3585 mex

orz PoPoQQQ. 本来蒟蒻以为这种离散化以后就对应不起来的题不能权值分块搞的说. ……结果,实际上>n的权值不会对答案作出贡献. #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 200002 #define BN 452 int n,m,num[N],a[N],l[BN],size[BN],anss[N],b[N],sumv[BN]; s

【带修莫队】【权值分块】bzoj3196 Tyvj 1730 二逼平衡树

这题用了三种算法写: 分块+二分:O(n*sqrt(n*log(n)) 函数式权值分块:O(n*sqrt(n)) 带修莫队+权值分块:O(n5/3) 结果……复杂度越高的实际上跑得越快……最后这个竟然进第一页了…… #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int f,C; inline void R(int &

D. Powerful array 离线+莫队算法 给定n个数,m次查询;每次查询[l,r]的权值; 权值计算方法:区间某个数x的个数cnt,那么贡献为cnt*cnt*x; 所有贡献和即为该区间的值;

D. Powerful array time limit per test 5 seconds memory limit per test 256 megabytes input standard input output standard output An array of positive integers a1,?a2,?...,?an is given. Let us consider its arbitrary subarray al,?al?+?1...,?ar, where 1?

XOR and Favorite Number(莫队算法+分块)

E. XOR and Favorite Number time limit per test 4 seconds memory limit per test 256 megabytes input standard input output standard output Bob has a favorite number k and ai of length n. Now he asks you to answer m queries. Each query is given by a pai