【BZOJ1901】Dynamic Rankings

Description

给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。

Input

对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

Output

 输出文件应包含T行。对于每一组数据,如果该关卡有解,输出一行Yes;否则输出一行No。

Sample Input

5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3

Sample Output

3
6

HINT

20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。

【分析】

裸的主席树,直接上模板就行了。

  1 /**************************************************************

  2     Problem: 1901

  3     User: TCtower

  4     Language: C++

  5     Result: Accepted

  6     Time:612 ms

  7     Memory:24988 kb

  8 ****************************************************************/

  9  

 10 #include <iostream>

 11 #include <cstring>

 12 #include <cstdio>

 13 #include <cmath>

 14 #include <cstring>

 15 #include <algorithm>

 16 #include <vector>

 17 //#define LOCAL

 18 const int maxn=10000+5;

 19 const int INF=99999999;

 20 const int maxnode=2000000+10; 

 21 using namespace std;

 22 struct OP

 23 {

 24        int type;//0代表询问,1代表改变 

 25        int l,r,k;

 26 }op[maxn];

 27 //点结构体 

 28 struct node

 29 {

 30        int ls,rs,w;

 31        node(){ls=rs=w=0;}

 32 }T[maxnode];

 33 vector<int>LX;

 34 vector<int>Q1,Q2;

 35 int a[maxn],n,q,n1;

 36 int cnt,root[maxn*2]; 

 37  

 38 void init();

 39 void work();

 40 //树状数组用 

 41 inline int lowbit(int i){return i&-i;}

 42 inline int find(int i)

 43 {

 44        //二分查找不解释 

 45        return (lower_bound(LX.begin(),LX.begin()+n1,i)-LX.begin())+1;

 46 }

 47 void build(int &i,int l,int r,int val);

 48 void query(int l,int r,int k);//区间第k大 

 49 //其实我觉得不传副本速度会上升? 

 50 int Qy(vector<int>Q1,vector<int>Q2,int l,int r,int k);

 51 void my_ins(int pos,int x,int v);

 52 void ins(int &i,int l,int r,int x,int v);

 53  

 54 int main() 

 55 {

 56     #ifdef LOCAL 

 57     freopen("data.txt","r",stdin);

 58     freopen("out.txt","w",stdout);

 59     #endif

 60     init();//读入与初始化 

 61     work();

 62     return 0;

 63 }

 64 void init()

 65 {

 66     scanf("%d%d",&n,&q);

 67     LX.clear();

 68     for (int i=1;i<=n;i++)

 69     {

 70         scanf("%d",&a[i]);        

 71         LX.push_back(a[i]);

 72     }

 73     char str[10];

 74     for (int i=1;i<=q;i++)

 75     {

 76         scanf("%s",str);

 77         if (str[0]=='Q')

 78         {

 79             op[i].type=0;

 80             scanf("%d%d%d",&op[i].l,&op[i].r,&op[i].k);

 81         }

 82         else

 83         {

 84             op[i].type=1;

 85             scanf("%d%d",&op[i].l,&op[i].r);

 86             LX.push_back(op[i].r);

 87         }

 88     }

 89     sort(LX.begin(),LX.end());

 90     n1=unique(LX.begin(),LX.end())-LX.begin();

 91 }

 92 void ins(int &i,int l,int r,int x,int v)

 93 {

 94      if (i==0) {T[++cnt]=T[i];i=cnt;}//没有创建过新的节点

 95      T[i].w+=v;

 96      if (l==r) return;

 97      int mid=(l+r)>>1;

 98      if (x<=mid) ins(T[i].ls,l,mid,x,v);

 99      else ins(T[i].rs,mid+1,r,x,v); 

100 }

101 void my_ins(int pos,int x,int v)

102 {

103      int t=find(x);//找到x的位置

104      for (int i=pos;i<=n;i+=lowbit(i))

105      {

106          ins(root[i],1,n1,t,v);

107      } 

108 }

109 int Qy(vector<int>Q1,vector<int>Q2,int l,int r,int k) 

110 {

111     if (l==r) return l;

112     int c=0,mid=(l+r)>>1;

113     //这两句可以互换,统计总数 

114     for (int i=0;i<Q1.size();i++) c-=T[T[Q1[i]].ls].w;

115     for (int i=0;i<Q2.size();i++) c+=T[T[Q2[i]].ls].w;

116     //大于k说明在左子树中而不右子树 

117     for (int i=0;i<Q1.size();i++) Q1[i]=(c>=k?T[Q1[i]].ls:T[Q1[i]].rs);

118     for (int i=0;i<Q2.size();i++) Q2[i]=(c>=k?T[Q2[i]].ls:T[Q2[i]].rs);

119     if (c>=k) return Qy(Q1,Q2,l,mid,k);//继续向下寻找 

120     else return Qy(Q1,Q2,mid+1,r,k-c);

121 } 

122 void query(int l,int r,int k)

123 {

124      Q1.clear();Q2.clear();//临时队列清空

125      Q1.push_back(root[l!=1?l-1+n:0]);

126      Q2.push_back(root[r+n]); 

127      for (int i=l-1;i;i-=lowbit(i)) Q1.push_back(root[i]);

128      for (int i=r;i;i-=lowbit(i)) Q2.push_back(root[i]);

129      int t=Qy(Q1,Q2,1,n1,k);

130      printf("%d\n",LX[t-1]);

131 } 

132 void work()

133 {

134      cnt=0;

135      memset(root,0,sizeof(root));

136      for (int i=1;i<=n;i++)

137      {

138          root[i+n]=root[i+n-1];

139          int t=find(a[i]);

140          build(root[i+n],1,n1,t);

141      }

142      for (int i=1;i<=q;i++)

143      {

144          if (op[i].type==0)

145          query(op[i].l,op[i].r,op[i].k);

146          else

147          {

148               my_ins(op[i].l,a[op[i].l],-1);

149               my_ins(op[i].l,op[i].r,1);

150               //修改 

151               a[op[i].l]=op[i].r;

152          }         

153      }

154 } 

155 void build(int &i,int l,int r,int val)

156 {

157      //对于修改过的每一个点

158      //都要新建一个副本 

159      T[++cnt]=T[i];i=cnt;

160      T[i].w++;

161      if (l==r) return;

162      int mid=(l+r)>>1;

163      //按值建线段树 

164      if (val<=mid) build(T[i].ls,l,mid,val);

165      else build(T[i].rs,mid+1,r,val);

166 }

 

你可能感兴趣的:(dynamic)