bzoj 3110 [Zjoi2013]K大数查询(树套树)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3110 [Zjoi2013]K大数查询(树套树)相关的知识,希望对你有一定的参考价值。
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操作中abs(c)<=Maxlongint
【思路】
线段树套线段树
里面的线段树基于区间,外面的线段树基于权值。我们就可以知道权值在[a,b]内且位置位于[c,d]内的数有多少个。
Add操作:在外面的线段树中找到c,将路径上经过的所有点对应的内层线段树区间[a,b]加1。
Query操作:在外面的线段树中通过询问对应的内层线段树结点的多少进行类似平衡树的转移。
线段树动态分配节点。
求第k大。。。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 6 using namespace std; 7 8 typedef long long ll; 9 const int N = 200000+10; 10 const int M = 20000000+10; 11 12 struct Tnode{ 13 int lc,rc,add,sum; 14 Tnode(){} 15 }T[M]; 16 17 int read() { 18 char c=getchar(); 19 int f=1,x=0; 20 while(!isdigit(c)) { 21 if(c==‘-‘) f=-1; c=getchar(); 22 } 23 while(isdigit(c)) 24 x=x*10+c-‘0‘,c=getchar(); 25 return x*f; 26 } 27 28 int n,m,sz; 29 int rt[M]; 30 31 void pushdown(int u,int l,int r) 32 { 33 if(!T[u].add || l==r) return ; 34 if(!T[u].lc) T[u].lc=++sz; 35 if(!T[u].rc) T[u].rc=++sz; 36 int v=T[u].add , mid=(l+r)>>1; 37 T[T[u].lc].add+=v; 38 T[T[u].rc].add+=v; 39 T[T[u].lc].sum+=v*(mid-l+1); 40 T[T[u].rc].sum+=v*(r-mid); 41 T[u].add=0; 42 } 43 void update(int &u,int l,int r,int L,int R) 44 { 45 if(!u) u=++sz; 46 pushdown(u,l,r); 47 if(L<=l&&r<=R) { 48 T[u].add++; 49 T[u].sum+=r-l+1; 50 } else { 51 int mid=(l+r)>>1; 52 if(L<=mid) update(T[u].lc,l,mid,L,R); 53 if(mid<R ) update(T[u].rc,mid+1,r,L,R); 54 T[u].sum=T[T[u].lc].sum+T[T[u].rc].sum; 55 } 56 } 57 int query(int u,int l,int r,int L,int R) 58 { 59 if(!u) return 0; 60 pushdown(u,l,r); 61 if(L<=l&&r<=R) return T[u].sum; 62 else { 63 int mid=(l+r)>>1,ans=0; 64 if(L<=mid) ans+=query(T[u].lc,l,mid,L,R); 65 if(mid<R ) ans+=query(T[u].rc,mid+1,r,L,R); 66 return ans; 67 } 68 } 69 void change(int a,int b,int c) 70 { 71 int u=1,l=1,r=n; 72 while(l!=r) { 73 int mid=(l+r)>>1; 74 update(rt[u],1,n,a,b); 75 if(c<=mid) r=mid,u=u<<1; 76 else l=mid+1,u=u<<1|1; 77 } 78 update(rt[u],1,n,a,b); 79 } 80 int query(int a,int b,int c) 81 { 82 int u=1,l=1,r=n; 83 while(l!=r) { 84 int mid=(l+r)>>1; 85 int t=query(rt[u<<1],1,n,a,b); 86 if(c<=t) r=mid,u=u<<1; 87 else l=mid+1,u=u<<1|1,c-=t; 88 } 89 return l; 90 } 91 92 int main() 93 { 94 //freopen("in.in","r",stdin); 95 //freopen("out.out","w",stdout); 96 n=read(),m=read(); 97 int op,a,b,c; 98 FOR(i,1,m) { 99 op=read(),a=read(),b=read(),c=read(); 100 if(op==1) { 101 change(a,b,n-c+1); 102 } else { 103 printf("%d\n",n-query(a,b,c)+1); 104 } 105 } 106 return 0; 107 }
以上是关于bzoj 3110 [Zjoi2013]K大数查询(树套树)的主要内容,如果未能解决你的问题,请参考以下文章