【ZJOI2013】k大数查询 BZOJ 3110

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操作中abs(c)<=Maxlongint

思路:

都是从浙江挂下来的考数据结构的歪风邪气←_←
一看就知道是数据结构题啦=。=
树套树。。我是写的树状数组套线段树。
外层的树状数组记录有关数字的信息,内层的线段树记录有关位置的信息。
也就是说我在[5,8]中加入了3这个数,就在外层的树状数组add_bit(3),然后在树状数组对应的节点上把[5,8]这个节点打上+1的标记。
每次对于一个询问[L,R]中第k大的数,我们先转化为求第k小,然后二分答案,寻找在[l,r]中有多少比Mid小的数,收缩上下界就行了。
p.s 网上说开树套树空间会爆,所以内层线段树要动态开点,我不知道要不要。。反正我是动态的。。不过跟静态的应该区别还是挺大的。
  1 #include <iostream>
  2 #include <cstring>
  3 #include <string>
  4 #include <cstdio>
  5 #include <cstdlib>
  6 #include <cmath>
  7 #include <algorithm>
  8 #include <queue>
  9 #include <stack>
 10 #include <map>
 11 #include <set>
 12 #include <list>
 13 #include <vector>
 14 #include <ctime>
 15 #include <functional>
 16 #define pritnf printf
 17 #define scafn scanf
 18 #define For(i,j,k) for(int i=(j);i<=(k);(i)++)
 19 #define Clear(a) memset(a,0,sizeof(a))
 20 using namespace std;
 21 typedef long long LL;
 22 typedef unsigned int Uint;
 23 const int INF=0x3fffffff;
 24 //==============struct declaration==============
 25 struct Node{
 26      Node *lc,*rc;
 27      long long sum,add;
 28      Node(){lc=rc=NULL;sum=add=0;}
 29 };
 30 //==============var declaration=================
 31 const int MAXN=80050;
 32 int n,m,L,R;
 33 long long sum[MAXN*2],addv[MAXN*2];
 34 Node *BitTree[MAXN];
 35 //==============function declaration============
 36 int lowbit(int x){return x&-x;}
 37 void add_bit(int x);
 38 void add_seg(Node *&o,int l,int r);
 39 long long  query_bit(int x);
 40 long long query_seg(Node *&i,int l,int r,long long add);
 41 void update(Node *&o,int l,int r);
 42 void add_num(int o,int l,int r);
 43 long long query_num(int o,int l,int r,long long add);
 44 //==============main code=======================
 45 int main()
 46 {
 47 #define FILE__
 48 #ifdef FILE__
 49     freopen("input","r",stdin);
 50     freopen("output","w",stdout);
 51 #endif
 52     scanf("%d%d",&n,&m);n++;
 53     for(int i=1;i<=n;i++) BitTree[i]=NULL;
 54     while (m--){
 55         int cmd,a,b;long long c;scanf("%d%d%d%lld",&cmd,&a,&b,&c);
 56         if (cmd==1){
 57              L=a;R=b;
 58              add_bit(c);add_num(1,1,n-1);
 59         }
 60         else if (cmd==2){
 61             int low=1,high=n-1,mid;
 62             L=a;R=b;
 63             long long Num_Exist=query_num(1,1,n-1,0);
 64             c=Num_Exist-c+1;
 65             while (low<high){
 66                 mid=(low+high)>>1;
 67                 long long tmp=query_bit(mid);
 68                 if (tmp<c)     low=mid+1;
 69                 if (tmp>=c)     high=mid;
 70             }
 71             printf("%d\n",low);
 72         }
 73     }
 74    return 0;
 75 }
 76 //================fuction code====================
 77 void add_bit(int x){
 78    while (x<=n){
 79        add_seg(BitTree[x],1,n-1);
 80        x+=lowbit(x);
 81    }
 82 }
 83 void add_seg(Node *&o,int l,int r){
 84     int m=(l+r)>>1;
 85     if (o==NULL)  o=new(Node);
 86     if (L<=l&&r<=R){
 87         o->add++;
 88         update(o,l,r);
 89         return;
 90     }
 91     if (m>=L)   add_seg(o->lc,l,m);
 92     if (m<R)    add_seg(o->rc,m+1,r);
 93     update(o,l,r);
 94 }
 95 void update(Node *&o,int l,int r){
 96     o->sum=0;
 97     if (o->lc!=NULL)    o->sum+=o->lc->sum;
 98     if (o->rc!=NULL)    o->sum+=o->rc->sum;
 99     o->sum+=(r-l+1)*o->add;
100 }
101 long long query_bit(int x){
102     long long res=0;
103     while (x>0){
104         res+=query_seg(BitTree[x],1,n-1,0);
105         x-=lowbit(x);
106     }
107     return res;
108 }
109 long long query_seg(Node *&o,int l,int r,long long add){
110     if (o==NULL)    return add*(min(r,R)-max(l,L)+1);
111     int m=(l+r)>>1;
112     if (L<=l&&r<=R)
113         return o->sum+(r-l+1)*add;
114     long long Left=0,Right=0;
115     if (m>=L)    Left=query_seg(o->lc,l,m,add+o->add);
116     if (m<R)    Right=query_seg(o->rc,m+1,r,add+o->add);
117     return Left+Right;
118 }
119 void add_num(int o,int l,int r){
120     if (L<=l&&r<=R){
121         addv[o]++;
122         sum[o]+=r-l+1;
123     }
124     else{
125         int lc=o*2,rc=o*2+1,m=(l+r)>>1;
126         if (m>=L)    add_num(lc,l,m);
127         if (m<R)    add_num(rc,m+1,r);
128         sum[o]=sum[lc]+sum[rc]+addv[o]*(r-l+1);
129     }
130 }
131 long long query_num(int o,int l,int r,long long add){
132     int lc=o*2,rc=o*2+1,m=(l+r)>>1;
133     if (L<=l&&r<=R)
134         return sum[o]+add*(r-l+1);
135     long long Left=0,Right=0;
136     if (m>=L)  Left=query_num(lc,l,m,add+addv[o]);
137     if (m<R)  Right=query_num(rc,m+1,r,add+addv[o]);
138     return Left+Right;
139 }
Prob_3110

   



posted @ 2015-02-27 09:57  Houjikan  阅读(172)  评论(0编辑  收藏  举报