bzoj3110[ZJOI2013]K大数查询 树套树
2017-02-12 15:30
218 查看
题目描述
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
输入输出格式
输入格式:
第一行N,M接下来M行,每行形如1 a b c或2 a b c
输出格式:
输出每个询问的结果
输入输出样例
输入样例#1:
2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
输出样例#1:
1
2
1
说明
【样例说明】
第一个操作 后位置 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
分析:
1.总体的思路可以是整体二分,权值线段树套区间线段树,线段树套Splay,线段树套主席树等,我用的是树套树中的权值线段树的做法
2.操作1中abs(c)<=N,因此我们可以用类似主席树的表示方法,在外层建立一颗权值线段树,每个节点表示一个权值区间的数的个数
3.而对于每一个节点,再建立一颗线段树来维护区间。
4.那么1操作就是权值线段树单点修改,区间线段树区间修改;2操作就是权值线段树区间查询,区间线段树区间查询
^_^
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
输入输出格式
输入格式:
第一行N,M接下来M行,每行形如1 a b c或2 a b c
输出格式:
输出每个询问的结果
输入输出样例
输入样例#1:
2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
输出样例#1:
1
2
1
说明
【样例说明】
第一个操作 后位置 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
分析:
1.总体的思路可以是整体二分,权值线段树套区间线段树,线段树套Splay,线段树套主席树等,我用的是树套树中的权值线段树的做法
2.操作1中abs(c)<=N,因此我们可以用类似主席树的表示方法,在外层建立一颗权值线段树,每个节点表示一个权值区间的数的个数
3.而对于每一个节点,再建立一颗线段树来维护区间。
4.那么1操作就是权值线段树单点修改,区间线段树区间修改;2操作就是权值线段树区间查询,区间线段树区间查询
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<map> using namespace std; typedef long long LL; const int maxn=50010; const int maxm=12000010; struct node{ int op; int a,b; LL c; }Q[maxn]; int ql,qr; int n,m; map<LL,int>mp; int num[maxn],val[maxn]; int node; int lc[maxm],rc[maxm]; LL sum[maxm],add[maxm]; int root[maxn<<4]; void modify(int &o,int l,int r){ if(!o) o=++node; int mid=(l+r)>>1; if(ql<=l && qr>=r){add[o]++;sum[o]+=(r-l+1);return;} if(ql<=mid) modify(lc[o],l,mid); if(qr>mid) modify(rc[o],mid+1,r); sum[o]=sum[lc[o]]+sum[rc[o]]+add[o]*(r-l+1); } LL query(int &o,int l,int r,LL addv){ if(!o) o=++node; int mid=(l+r)>>1; if(ql<=l && qr>=r) return sum[o]+addv*(r-l+1); LL ret=0; if(ql<=mid) ret+=query(lc[o],l,mid,addv+add[o]); if(qr>mid) ret+=query(rc[o],mid+1,r,addv+add[o]); return ret; } int cnt; int main(){ scanf("%d%d",&n,&m); int L,R,now; for(int i=1;i<=m;i++){ scanf("%d%d%d%lld",&Q[i].op,&Q[i].a,&Q[i].b,&Q[i].c); if(Q[i].op==1) num[++cnt]=Q[i].c; } sort(num+1,num+1+cnt); int nm=0; for(int i=1;i<=m;i++) if(i==1 || num[i]!=num[i-1]) mp[num[i]]=++nm,val[nm]=num[i]; LL c; for(int i=1;i<=m;i++){ ql=Q[i].a,qr=Q[i].b; now=1,L=1,R=n; c=Q[i].c; if(Q[i].op==1){ c=mp[c]; while(L<R){ modify(root[now],1,n); int mid=(L+R)>>1; if(c<=mid) R=mid,now=now<<1; else L=mid+1,now=now<<1|1; } modify(root[now],1,n); }else{ do{ LL t=query(root[now<<1|1],1,n,0); int mid=(L+R)>>1; if(t>=c) L=mid+1,now=now<<1|1; else R=mid,now=now<<1,c-=t; }while(L<R); printf("%d\n",val[L]); } } return 0; }
^_^
相关文章推荐
- BZOJ3110: [Zjoi2013]K大数查询
- Bzoj3110 [Zjoi2013]K大数查询
- BZOJ3110 [ZJOI2013] K大数查询
- BZOJ3110:[ZJOI2013]K大数查询——题解
- bzoj3110 zjoi2013 K大数查询
- bzoj3110 zjoi2013 K大数查询
- bzoj3110 [Zjoi2013]K大数查询
- BZOJ3110: [Zjoi2013]K大数查询
- BZOJ3110: [Zjoi2013]K大数查询
- bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】
- BZOJ3110 ZJOI2013 K大数查询
- bzoj3110[Zjoi2013]K大数查询
- bzoj3110 [Zjoi2013]K大数查询(整体二分)
- bzoj3110【ZJOI2013】K大数查询
- bzoj3110: [Zjoi2013]K大数查询
- bzoj3110: [Zjoi2013]K大数查询
- bzoj3110 [Zjoi2013]K大数查询
- bzoj3110[Zjoi2013]K大数查询
- BZOJ3110: [Zjoi2013]K大数查询
- [整体二分] BZOJ3110: [Zjoi2013]K大数查询