树套树

ZJOI2013 K大数

权值线段树+区间线段树
对权值线段树每一个节点开一个区间线段树,动态开点。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=5e4+10;
struct TREE{
	long long sum,f;
	int l,r;
}tree[N*400];
struct NODE{
	int opt,l,r;
	long long c;
}node[N];
int root[N*4];
long long h[N];
int n,m,cnt,tot;
void pushdown(int x,int ll,int rr)
{
	if(tree[x].f)
	{	
		if(!tree[x].l)  	tree[x].l=++tot;	//注意这个添点操作!!! 
		if(!tree[x].r)		tree[x].r=++tot;
		int l=tree[x].l;		int r=tree[x].r; 
		int mid=(ll+rr)>>1;
		tree[l].sum+=tree[x].f*(mid-ll+1);		tree[l].f+=tree[x].f; //注意乘以区间长度!!! 
		tree[r].sum+=tree[x].f*(rr-mid);		tree[r].f+=tree[x].f; 
		tree[x].f=0;
	}
}
void insert(int &x,int l,int r,int ll,int rr)
{
	if(!x)
		x=++tot;
	if(ll<=l&&r<=rr)
	{
		tree[x].sum+=r-l+1;		tree[x].f++; //注意加上区间长度!!! 
		return;
	}
	int mid=(l+r)>>1;
	pushdown(x,l,r); //pushdown !!! 
	if(ll<=mid)		insert(tree[x].l,l,mid,ll,rr);
	if(rr>mid) 		insert(tree[x].r,mid+1,r,ll,rr);
	tree[x].sum=tree[tree[x].l].sum+tree[tree[x].r].sum; // pushup!!! 
}
void ins(int x,int l,int r,int v,int a,int b)
{
	insert(root[x],1,n,a,b); //每经过一个点都要insert!!! 
	if(l==r) 	return;
	int mid=(l+r)>>1;
	if(v>mid) 	ins(x*2+1,mid+1,r,v,a,b);
	else 		ins(x*2,l,mid,v,a,b);
}
long long query(int x,int l,int r,int ll,int rr,long long v)
{
	if(!x)	return 0;
	if(ll<=l&&r<=rr)		return tree[x].sum;
	pushdown(x,l,r); //pushdown!!! 
	int mid=(l+r)>>1; 
	if(ll>mid)	 return query(tree[x].r,mid+1,r,ll,rr,v);
	if(rr<=mid)	 return query(tree[x].l,l,mid,ll,rr,v);
	return query(tree[x].l,l,mid,ll,rr,v)+query(tree[x].r,mid+1,r,ll,rr,v);
}
long long qry(int x,int l,int r,long long v,int a,int b)
{
	if(l==r) 	return h[l];
	int mid=(l+r)>>1;
	long long size=query(root[x*2+1],1,n,a,b,v);
	if(size<v)	return qry(x*2,l,mid,v-size,a,b);
	else		return qry(x*2+1,mid+1,r,v,a,b);
}
int main()
{
	int tcnt=0;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d%lld",&node[i].opt,&node[i].l,&node[i].r,&node[i].c);
		if(node[i].opt==1) 	h[++tcnt]=node[i].c;
	}
	sort(h+1,h+tcnt+1);
	cnt=unique(h+1,h+tcnt+1)-h-1;
	for(int i=1;i<=m;i++)
	{
		if(node[i].opt==1)
		{
			int c=lower_bound(h+1,h+cnt+1,node[i].c)-h; //传int和传longlong时间差很多
			ins(1,1,cnt,c,node[i].l,node[i].r);
		}
		else
			printf("%lld\n",qry(1,1,cnt,node[i].c,node[i].l,node[i].r));
	}
	return 0;
}
/*
2 7
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
1 1 1 2 
2 1 1 3 
*/ 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值