【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

   



你可能感兴趣的:(ZOJ)