HDU 4006 离散化+权值线段树+线段树二分

The kth great number

 
题目大意:
I操作表示在数列中添加一个数(序列最初为空)
Q操作表示求 数列中第k大的数

解题思路:
由于要求 数列中第k大的数,因此考虑使用 权值线段树。(详见  

UESTC 841 权值线段树

但是数据范围是10^6,考虑 离散化。
枚举每一次操作,将选出的数压入线段树。求后缀和为k的数的编号:
线段树二分,对于线段树的每一个结点,如果它右儿子的区间和大于等于k,则在右儿子中继续直到找到根节点。
                                                                  否则,在左儿子中找k=k- 右儿子的区间和,递归到根节点。
最后注意离散化的还原和读入输出优化
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long

const int N=1000010;
const int MAX=1e9+7;
int n,k;
struct Q
{
	char c;
	int a;
	int b;
}q[N];
struct ha
{
	int num;
	int b;
	int hao;
}a[N];
int len;
int d[N];

inline void R(int &v)//读入优化(必加,否则TLE) 
{
	v=0;
	char ch=getchar();
	int f=0;
	while(!isdigit(ch)){if(ch=='-')f=1;ch=getchar();}
	while(isdigit(ch)){v=(v<<3)+(v<<1)+ch-'0';ch=getchar();}
	if(f) v=-v;
}
namespace ib {char b[100];}
inline void P(int x)//输出优化(必加,否则TLE) 
{
    if(x==0) {putchar(48); return;}
    if(x<0) {putchar('-'); x=-x;}
    char *s=ib::b;
    while(x) *(++s)=x%10, x/=10;
    while(s!=ib::b) putchar((*(s--))+48);
}
struct Segtree
{
	struct trie
	{
		int l,r,len;
		int sum;
		int lz;
	}tree[N<<2];
	
	void updata(int o)//更新 
	{
		tree[o].sum=tree[o<<1].sum+tree[o<<1|1].sum;
	}
	
	void build(int o,int l,int r)//建树 
	{
		tree[o].sum=0;
		tree[o].l=l;
		tree[o].r=r;
		tree[o].len=r-l+1;
		if(l==r) {tree[o].sum=0;return;}
		int mid=(l+r)>>1;
		build(o<<1,l,mid);
		build(o<<1|1,mid+1,r);
		updata(o);
	}
	
	void change(int o,int q,int v)//单点加 
	{
		int l=tree[o].l,r=tree[o].r;
		if(l==r) {tree[o].sum+=v;return;}
		int mid=l+r>>1;
		if(q<=mid) change(o<<1,q,v);
		else change(o<<1|1,q,v);
		updata(o);
	}
	
	int find(int o,int k)//线段树二分查找后缀和(必须为单调序列)  
	{
		if(tree[o].l==tree[o].r) return tree[o].l; 
		int lo=o<<1,ro=o<<1|1;
		if(tree[ro].sum>=k) return find(ro,k);
		else return find(lo,k-tree[ro].sum);
	}
}A;

void init()//初始化 
{
	len=0;
	memset(d,0,sizeof(d));
	memset(a,0,sizeof(a));
}

bool cmp(const ha &a,const ha &b)
{
	return a.num
结语:
*离散化、*权值线段树、*线段树二分
较有难度的线段树题目。了解算法以后思路清晰才能写好。
线段树二分还会有很多应用,要熟练掌握。



你可能感兴趣的:(线段树)