BZOJ 3110: [Zjoi2013]K大数查询 [树套树]
Posted Candy?
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3110: [Zjoi2013]K大数查询 [树套树]相关的知识,希望对你有一定的参考价值。
3110: [Zjoi2013]K大数查询
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6050 Solved: 2007
[Submit][Status][Discuss]
Description
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
Input
第一行N,M
接下来M行,每行形如1 a b c或2 a b c
Output
输出每个询问的结果
Sample Input
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
Sample Output
2
1
HINT
【样例说明】
第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1
的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是
1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3
大的数是 1 。
N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=Maxlongint
本题做法好多啊,人太弱先写权值线段树套区间线段树吧
蒟蒻无脑总结:树套树是一种二维数据结构,用来解决二维的信息修改和询问
本题两个信息,一段区间中保存数,求第k大
显然用一个区间数据结构一个可求排名的数据结构,可以用权值线段树和区间线段树
区间线段树在外层,维护增加数的信息好难啊
权值线段树在外层,每个节点放一颗区间线段树维护这个节点权值在区间中出现次数
修改...修改就行了啊
查询,在权值线段树上二分答案,只不过用的是[a,b]中的出现次数
复杂度nlog^2n
参考别人写的,好诡异啊,明明有范围那么大还有负数,不离散化也能A
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define m ((l+r)>>1) #define lc t[o].l #define rc t[o].r #define lson t[o].l,l,m #define rson t[o].r,m+1,r const int N=5e4+5; typedef long long ll; inline int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();} return x*f; } int n,Q,op,ql,qr,v; struct node{ int l,r; ll sum,tag; }t[N*300]; int sz; inline void merge(int o){ t[o].sum=t[lc].sum+t[rc].sum; } inline void paint(int &o,int l,int r,ll d){ if(!o) o=++sz; t[o].sum+=(ll)(r-l+1)*d; t[o].tag+=d; } inline void pushDown(int o,int l,int r){ if(t[o].tag){ paint(lson,t[o].tag); paint(rson,t[o].tag); t[o].tag=0; } } void add(int &o,int l,int r,int ql,int qr,int d){ if(!o) o=++sz; if(ql<=l&&r<=qr) paint(o,l,r,d); else{ pushDown(o,l,r); if(ql<=m) add(lson,ql,qr,d); if(m<qr) add(rson,ql,qr,d); merge(o); } } ll query(int o,int l,int r,int ql,int qr){ if(!o) return 0; if(ql<=l&&r<=qr) return t[o].sum; else{ pushDown(o,l,r); ll ans=0; if(ql<=m) ans+=query(lson,ql,qr); if(m<qr) ans+=query(rson,ql,qr); return ans; } } int rt[N<<2]; void add2(int o,int l,int r,int ql,int qr,int v){ add(rt[o],1,n,ql,qr,1); if(l==r) return; if(v<=m) add2(o<<1,l,m,ql,qr,v); else add2(o<<1|1,m+1,r,ql,qr,v); } ll query2(int o,int l,int r,int ql,int qr,int k){ if(l==r) return l; ll rsize=query(rt[o<<1|1],1,n,ql,qr); if(rsize>=k) return query2(o<<1|1,m+1,r,ql,qr,k); else return query2(o<<1,l,m,ql,qr,k-rsize); } int main(){ //freopen("in.txt","r",stdin); n=read();Q=read(); while(Q--){ op=read();ql=read();qr=read();v=read(); if(op==1) add2(1,1,n,ql,qr,v); else printf("%lld\n",query2(1,1,n,ql,qr,v)); } }
以上是关于BZOJ 3110: [Zjoi2013]K大数查询 [树套树]的主要内容,如果未能解决你的问题,请参考以下文章