树套树——BZOJ3110/Luogu3332 [ZJOI2013]K大数查询

http://www.lydsy.com/JudgeOnline/problem.php?id=3110
https://www.luogu.org/problem/show?pid=3332
带插入的区间k值啊。。。
这个啊,用主席树我不会做,这个我只会树套树
外层权值线段树,内层区间线段树
把k大改成k小很简单,取反即可哦(很方便因为abs(c)<=n)
然后介绍一下思路
外层修改和查找时的过程等同于找链,类似于二分
内层等同于线段树区间修改和区间查询
意义呢其实和前面的poj题目是差不多的
感觉我的程序有bug但是居然AC了,欢迎hack
这题还有整体二分的做法。。。博主太懒了QAQ。。。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned int in;
inline in read(){
    in k=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
    return k*f;
}
in root[200001],t[10000001],lt[10000001],rt[10000001],add[10000001],cnt=0;//数组开大点
in n,m,x,y,z;
inline void nxg(in l,in r,in& nod){//内层修改
    if(!nod)nod=++cnt;
    if(l>=x&&r<=y){add[nod]++;t[nod]+=r-l+1;return;}
    in mid=(l+r)>>1;
    if(x<=mid)nxg(l,mid,lt[nod]);
    if(y>mid)nxg(mid+1,r,rt[nod]);
    t[nod]=t[lt[nod]]+t[rt[nod]]+add[nod]*(r-l+1);
}
inline void xg(in l,in r,in nod){//外层修改
    while(1){
        nxg(1,n,root[nod]);
        if(l==r)return;
        in mid=(l+r)>>1;
        if(z<=mid){r=mid;nod*=2;continue;}
        l=mid+1;(nod*=2)++;
    }
}
inline in ns(in l,in r,in nod){//内层查询
    if(!nod)return 0;
    if(l>=x&&r<=y)return t[nod];
    in mid=(l+r)>>1,sum=0;
    if(x<=mid)sum+=ns(l,mid,lt[nod]);
    if(y>mid)sum+=ns(mid+1,r,rt[nod]);
    return sum+add[nod]*(min(y,r)-max(l,x)+1);
}
inline in s(in l,in r,in nod){//外层查询
    while(1){
        if(l==r)return l;
        in mid=(l+r)>>1,cmp=ns(1,n,root[nod*2]);
        if(z<=cmp){r=mid;nod*=2;continue;}
        z-=cmp;l=mid+1;(nod*=2)++;
    }
}
int main()
{
    n=read();m=read();
    for(in i=1;i<=m;i++){
        in c=read();x=read();y=read();z=read();
        if(c==1)z=n-z+1,xg(1,n,1);//取个反求k小
        else printf("%d\n",n-s(1,n,1)+1);//再取个反就是k大啦
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值