[luogu] P2617 Dynamic Rankings

整体二分模板,所谓整体二分其实就是将修改与询问保存下来,然后二分值域;

树套树亦可,但是码量较大;

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;const int N=1e5+7;typedef long long ll;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<‘0‘||ch>‘9‘)	{if(ch==‘-‘) f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘)	{x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
struct Query
{
	int o,l,r,k,i;
	Query(int o=0,int l=0,int r=0,int k=0,int i=0)
	{this->o=o;this->l=l;this->r=r;this->k=k;this->i=i;}
}q[N<<2],q1[N<<2],q2[N<<2];int n,m,c[N],w[N],res[N];
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int y){for(int i=x;i<=n;i+=lowbit(i))c[i]+=y;}
inline int sum(int x){int res=0;while(x)res+=c[x],x-=lowbit(x);return res;}
inline void solve(int s,int t,int l,int r)
{
	if(l==r)
	{
		for(int i=s;i<=t;i++)
		if(q[i].o==2)res[q[i].i]=l;
		return;
	}int mid=(l+r)>>1,cnt1=0,cnt2=0;
	for(int i=s;i<=t;i++)
	{
		if(q[i].o==1)
		{
			if(q[i].l<=mid) add(q[i].i,q[i].r),q1[++cnt1]=q[i];
			else q2[++cnt2]=q[i];
		}
		else
		{
			int x=sum(q[i].r)-sum(q[i].l-1);
			if(x>=q[i].k) q1[++cnt1]=q[i];
			else q[i].k-=x,q2[++cnt2]=q[i];
		}
	}
	for(int i=1;i<=cnt1;i++)
	if(q1[i].o==1)add(q1[i].i,-q1[i].r);
	for(int i=1;i<=cnt1;i++) q[s+i-1]=q1[i];
	for(int i=1;i<=cnt2;i++) q[s+cnt1+i-1]=q2[i];
	if(cnt1) solve(s,s+cnt1-1,l,mid);
	if(cnt2) solve(s+cnt1,t,mid+1,r);
}
int main()
{
	n=read(),m=read();int cnt=0,tot=0;
	for(int i=1;i<=n;i++) q[++cnt]=Query(1,w[i]=read(),1,0,i);
	for(int i=1;i<=m;i++)
	{
		char ch;cin>>ch;
		if(ch==‘Q‘) q[++cnt].o=2,q[cnt].l=read(),q[cnt].r=read(),q[cnt].k=read(),q[cnt].i=++tot;
		else
		{
			int l=read(),r=read();
			q[++cnt]=Query(1,w[l],-1,0,l);
			q[++cnt]=Query(1,w[l]=r,1,0,l);
		}
	}solve(1,cnt,0,1e9+1);
	for(int i=1;i<=tot;i++)	cout<<res[i]<<endl;
	return 0;
}

原文地址:https://www.cnblogs.com/chtomede/p/12082942.html

时间: 2024-07-31 06:15:22

[luogu] P2617 Dynamic Rankings的相关文章

luogu P2617 Dynamic Rankings(分块,n &lt;= 1e4)

嘟嘟嘟 带修改区间第k大. 然而某谷把数据扩大到了1e5,所以用分块现在只能得50分. 分块怎么做呢?很暴力的. 基本思想还是块内有序,块外暴力统计. 对于修改,直接重排修改的数所在块,时间复杂度O(√nlogn√n). 对于询问,二分答案,然后在每个块内再二分统计小于mid的数有几个,块外暴力统计,时间复杂度O(m * log1e9 * √nlog√n),所以只能过1e4. 1 #include<cstdio> 2 #include<iostream> 3 #include<

P2617 Dynamic Rankings

题目链接:https://www.luogu.org/problem/P2617 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题.你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令. 对于每一个询问指令,你必

P2617 Dynamic Rankings(带修主席树)

所谓带修主席树,就是用树状数组的方法维护主席树的前缀和 思路 带修主席树的板子 注意数据范围显然要离散化即可 代码 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct Node{ int sz,lson,rson; }PT[100100*400]; struct Q{ char c; int l,r,x,val; }opt[100100]; const

P2617 Dynamic Rankings(主席树+树状数组)

怕是还没有题解,所以先写一篇. 这题就是维护带修改的主席树.首先树套树肯定是能做的,既然树套树能做那么整体二分肯定也是可以的. 由于我并没有使用这两种做法,所以此处不予介绍. 大概描述下主席树的思路: 首先说说怎么搞带修改主席树? 回忆一般的kth问题,我们的主席树求的是前缀和,这样我们在目标区间的左右端点的主席树差分下就能求出kth. 那么我们如何支持修改操作? 考虑到我们之前使用主席树朴素的维护区间前缀和,支持修改的话,只要把前缀和交给擅长它的树状数组维护,主席树只要维护下位置就好. 1 #

P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)

题意:带修求区间k小 题解:回忆在使用主席树求区间k小时 利用前缀和的思想 既然是前缀和 那么我们可以使用更擅长维护前缀和的树状数组 但是这里每一颗权值线段树就不是带版本的 而是维护数组里i号点的权值信息 所以实际上并不是主席树 每一棵和前面一棵并没有共用结点 对于一次修改操作 我们先删去这个点的原信息 再更新进去 树状数组上的点一起跳 可能看代码比较好理解一点 这个方法限制性也很强 必须离线 #include <bits/stdc++.h> using namespace std; cons

BZOJ 1901 Dynamic Rankings

题面: 1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 8088  Solved: 3364[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1 ],a[i+2]--a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变

1901: Zju2112 Dynamic Rankings

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5268  Solved: 2207[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i

【BZOJ-1901】Dynamic Rankings 带修主席树

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7292  Solved: 3038[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i

[bzoj1901][zoj2112][Dynamic Rankings]

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They