3110: [Zjoi2013]K大数查询
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9905 Solved: 2945
[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
2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
Sample Output
1
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
第一次接触树套树
树套树就是把外层树的每个节点重新开一个树,由于空间要求太大,要动态开点
对于此题来说,外层权值线段树,内层区间线段树
查询时,在权值树上向右儿子找在[l,r]的个数,如果不够就要向左走,否则向右
bzoj数据有负数,注意离散和long long问题
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define ll long long #define N 50050 #define M N<<8 using namespace std; int n,m,tot,cnt,str[N],rt[N<<2],ls[M],rs[M],lz[M];ll sum[M]; struct ask{int op,a,b,c;}q[N]; void pushdown(int u,int l,int r){ if(!lz[u])return; int mid=l+r>>1,x=lz[u]; if(!ls[u])ls[u]=++cnt; if(!rs[u])rs[u]=++cnt; sum[ls[u]]+=x*(mid-l+1); sum[rs[u]]+=x*(r-mid); lz[ls[u]]+=x;lz[rs[u]]+=x; lz[u]=0; } void update(int &u,int L,int R,int l,int r){ if(!u)u=++cnt; if(l<=L&&R<=r){ sum[u]+=R-L+1; lz[u]++; return; }pushdown(u,L,R); int mid=L+R>>1; if(l<=mid)update(ls[u],L,mid,l,r); if(r>mid)update(rs[u],mid+1,R,l,r); sum[u]=sum[ls[u]]+sum[rs[u]]; } void add(int u,int L,int R,int l,int r,int p){ update(rt[u],1,n,l,r); if(L==R)return; int mid=L+R>>1; if(p<=mid)add(u<<1,L,mid,l,r,p); else add(u<<1|1,mid+1,R,l,r,p); } ll query(int u,int L,int R,int l,int r){ if(l<=L&&R<=r)return sum[u]; pushdown(u,L,R); int mid=L+R>>1;ll tt=0; if(l<=mid)tt+=query(ls[u],L,mid,l,r); if(r>mid)tt+=query(rs[u],mid+1,R,l,r); return tt; } int calc(int u,int L,int R,int l,int r,ll k){ if(L==R)return L; int mid=L+R>>1; ll tmp=query(rt[u<<1|1],1,n,l,r); if(tmp>=k)return calc(u<<1|1,mid+1,R,l,r,k); return calc(u<<1,L,mid,l,r,k-tmp); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d%d",&q[i].op,&q[i].a,&q[i].b,&q[i].c); if(q[i].op==1)str[++tot]=q[i].c; } sort(str+1,str+1+tot); int len=unique(str+1,str+1+tot)-str-1; for(int i=1;i<=m;i++){ int op=q[i].op,a=q[i].a,b=q[i].b,c=q[i].c; if(op==1)c=lower_bound(str+1,str+1+len,c)-str; if(op==1)add(1,1,len,a,b,c); else printf("%d ",str[calc(1,1,len,a,b,c)]); } return 0; }