洛谷 P2617 Dynamic Rankings(毒瘤卡常题 带修主席树/TLE的树套树)

题目描述
一道垃圾的区间带修第k大写了一天
线段树套splay TLE
优化成两个log TLE
套替罪羊树 TLE
套权值线段树 TLE

算了吧,就当模板带修主席树吧
带修主席树这玩意真暴力
就用个树状数组把一堆线段树套起来
然后求的时候把每个树状数组里的点都暴力提取出来,直接暴力对每个点对应的数统计答案,树上二分
模板题也没什么好说的,垃圾……

代码如下:

#include<bits/stdc++.h>
#define lson tr[now].l
#define rson tr[now].r
using namespace std;

inline int lowbit(int x)
{
   
	return x&(-x);
}

struct tree
{
   
	int l,r,sum;
}tr[40000030];

int cnt,rt[400020];
int tota,totb,tmpa[400020],tmpb[400020];
int a[400020],tot,b[400020];
int n,m;

struct que
{
   
	int kd,l,r,val;
}q[400020];

void insert(int &now,int pre,int l,int r,int pos,int val)
{
   
	now=++cnt;
	tr[now]=tr[pre];
	tr[now].sum+=val;
	if(l==r)
	{
   
		return ;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) insert(lson,tr[pre].l,l,mid,pos,val);
	else insert(rson,tr[pre].r,mid+1,r,pos,val);
}

int query(int l,int r,int kk)
{
   
	if(l==r)
	{
   
		return b[l];
	}
	int mid=(l+r)>>1;
	int sz=0;
	for(int i=1;i<=tota;i++) sz+=tr[tr[tmpa[i]].l].sum;
	for(int i=1;i<=totb;i++) sz-=tr[tr[tmpb[i]].l].sum;
	if(kk<=sz)
	{
   
		for(int i=1;i<=tota;i++) tmpa[i]=tr[tmpa[i]].l;
		for(int i=1;i<=totb;i++) tmpb[i]=tr[tmpb[i]].l;
		return query(l,mid,kk);
	}
	else
	{
   
		for(int i=1;i<=tota;i++) tmpa[i]=tr[tmpa[i]].r;
		for(int i=1;i<=totb;i++) tmpb[i]=tr[tmpb[i]].r;
		return query(mid+1,r,kk-sz);
	}

}

void add(int pos,int val)
{
   
	int vp=lower_bound(b+1,b+tot+1,a[pos])-b;
	for(int i=pos;i<=n;i+=lowbit(i))
	{
   
		insert(rt[i],rt[i],1,tot,vp,val);
	}
}

int get(int l,int r,int kk)
{
   
	tota=0,totb=0;
	for(int i=r;i>0;i-=lowbit(i)) tmpa[++tota]=rt[i];
	for(int i=l-1;i>0;i-=lowbit(i)) tmpb[++totb]=rt[i];
	return query(1,tot,kk);
}

char s[10];

int main()
{
   
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[++tot]=a[i];
	for(int i=1;i<=m;i++)
	{
   
		scanf("%s",s);
		if(s[0]=='Q') 
		{
   
			q[i].kd=0;
			scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].val);
		}
		else
		{
   
			q[i].kd=1;
			scanf("%d%d",&q[i].l,&q[i].val);
			b[++tot]=q[i].val;
		}
	}
	sort(b+1,b+tot+1);
	tot=unique(b+1,b+tot+1)-b-1;
	for(int i=1;i<=n;i++) add(i,1);
	for(int i
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值