Description
Wind loves pretty dogs very much, and she has n pet dogs. So Jiajia has to feed the dogs every day for Wind. Jiajia loves Wind, but not the dogs, so Jiajia use a special way to feed the dogs. At lunchtime, the dogs will stand on one line, numbered from 1 to n, the leftmost one is 1, the second one is 2, and so on. In each feeding, Jiajia choose an inteval[i,j], select the k-th pretty dog to feed. Of course Jiajia has his own way of deciding the pretty value of each dog. It should be noted that Jiajia do not want to feed any position too much, because it may cause some death of dogs. If so, Wind will be angry and the aftereffect will be serious. Hence any feeding inteval will not contain another completely, though the intervals may intersect with each other.
Your task is to help Jiajia calculate which dog ate the food after each feeding.
Your task is to help Jiajia calculate which dog ate the food after each feeding.
Input
The first line contains n and m, indicates the number of dogs and the number of feedings.
The second line contains n integers, describe the pretty value of each dog from left to right. You should notice that the dog with lower pretty value is prettier.
Each of following m lines contain three integer i,j,k, it means that Jiajia feed the k-th pretty dog in this feeding.
You can assume that n<100001 and m<50001.
The second line contains n integers, describe the pretty value of each dog from left to right. You should notice that the dog with lower pretty value is prettier.
Each of following m lines contain three integer i,j,k, it means that Jiajia feed the k-th pretty dog in this feeding.
You can assume that n<100001 and m<50001.
Output
Output file has m lines. The i-th line should contain the pretty value of the dog who got the food in the i-th feeding.
Sample Input
7 2 1 5 2 6 3 7 4 1 5 3 2 7 1
Sample Output
32
神题啊,线段树,树状数组,Treap,SBT,Splay都可以做。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define maxn 200080
int A[maxn],Ans[maxn];
struct Que
{
int from,to,k,id;
}que[maxn>>1];
bool cmp(Que a,Que b)
{
if(a.from < b.from) return 1;
else if(a.from > b.from) return 0;
else return a.to < b.to;
}
struct Node
{
Node * ch[2];
int r,v,s;
/*
bool operator < (const Node & a) const
{
return r < a.r;
}
*/
int cmp(int x) const
{
if(x == v) return -1;
return x < v?0:1;
}
void maintain()
{
s = 1;
if(ch[0] != NULL) s += ch[0] -> s;
if(ch[1] != NULL) s += ch[1] -> s;
}
}*root;
void rotate(Node *& o,int d)
{
Node * k = o -> ch[d^1];
o -> ch[d^1] = k -> ch[d];
k -> ch[d] = o;
o -> maintain();
k -> maintain();
o = k;
}
void insert(Node *& o,int x)
{
if(o == NULL)
{
o = new Node();
o -> ch[0] = o -> ch[1] = NULL;
o -> v = x;
o -> r = rand();
o -> s = 1;
}
else
{
int d = o -> cmp(x);
if(d == -1) d = 0;
insert(o -> ch[d],x);
if(o -> ch[d] -> r > o -> r)
rotate(o,d^1);
}
o -> maintain();
}
void remove(Node *& o,int x)
{
int d = o -> cmp(x);
if(d == -1)
{
Node * tmp = o;
if(o -> ch[0] == NULL)
{
o = o -> ch[1];
delete tmp;
tmp = NULL;
}
else if(o -> ch[1] == NULL)
{
o = o -> ch[0];
delete tmp;
tmp = NULL;
}
else
{
int d2 = (o -> ch[0] -> r > o -> ch[1] -> r?1:0);
rotate(o,d2);
remove(o -> ch[d2],x);
}
}
else remove(o -> ch[d],x);
if(o != NULL) o -> maintain();
}
bool find(Node * o,int x)
{
while(o != NULL)
{
int d = o -> cmp(x);
if(d == -1) return 1;
else o = o -> ch[d];
}
return 0;
}
int Rank(Node * o,int x)
{
int ans = 0;
while(o)
{
if(o -> v == x)
{
if(o -> ch[0]) ans += o -> ch[0] -> s;
return ans;
}
else if(o -> v > x)
{
o = o -> ch[0];
}
else
{
if(o -> ch[0]) ans += o -> ch[0] -> s;
ans++;
o = o -> ch[1];
}
}
return ans;
}
int Kth(Node * o,int k)
{
while(k)
{
if(o -> ch[0])
{
if(o -> ch[0] ->s >= k) o = o -> ch[0];
else if(o -> ch[0] -> s == k-1) return o -> v;
else k -= o -> ch[0] -> s + 1,o = o -> ch[1];
}
else if( k == 1 ) return o -> v;
else k--,o = o -> ch[1];
}
}
void DeleteTreap(Node *& o)
{
if(o == NULL) return;
if(o -> ch[0]) DeleteTreap(o -> ch[0]);
if(o -> ch[1]) DeleteTreap(o -> ch[1]);
delete o;
o = NULL;
}
int main()
{
//freopen("in.txt","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
root = NULL;
for(int i = 0;i < n;i++)
{
scanf("%d",&A[i]);
///insert(root,A[i]);
}
for(int i = 0;i < m;i++)
{
scanf("%d%d%d",&que[i].from,&que[i].to,&que[i].k);
que[i].from--;que[i].to--;
que[i].id = i+1;
}
sort(que,que+m,cmp);
for(int i = que[0].from;i <= que[0].to;i++)
{
insert(root,A[i]);
}
Ans[que[0].id] = Kth(root,que[0].k);
int l = que[0].from,r = que[0].to;
for(int i = 1;i < m;i++)
{
if(r >= que[i].from)
{
if(l < que[i].from)
for(int j = l;j < que[i].from;j++) remove(root,A[j]);
else if(l > que[i].from)
for(int j = que[i].from;j < l;j++) insert(root,A[j]);
if(r < que[i].to)
for(int j = r+1;j <= que[i].to;j++) insert(root,A[j]);
else if(r > que[i].to)
for(int j = que[i].to+1;j <= r;j++) remove(root,A[j]);
}
else
{
for(int j = l;j <= r;j++) remove(root,A[j]);
for(int j = que[i].from;j <= que[i].to;j++) insert(root,A[j]);
}
Ans[que[i].id] = Kth(root,que[i].k);
l = que[i].from,r = que[i].to;
}
for(int i = 1;i <= m;i++) printf("%d\n",Ans[i]);
DeleteTreap(root);
}
return 0;
}
接下来是线段树做法:
/*
首先将数据离散化。
然后节点表示这段区间的数有多少个。
update函数用来添点删点。
二分查找就行。
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 100080
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
int X[maxn],XX[maxn],Ans[maxn];
struct Que
{
int from,to,k,id;
}que[maxn];
bool cmp(Que a,Que b)
{
if(a.from < b.from) return 1;
else if(a.from > b.from) return 0;
else return a.to < b.to;
}
struct ST
{
int l,r,num;
}st[maxn<<2];
void PushUp(int id)
{
st[id].num = st[id<<1].num + st[id<<1|1].num;
}
void buildtree(int id,int l,int r)
{
st[id].l = l,st[id].r = r;
if(l == r)
{
st[id].num = 0;
return;
}
int mid = (l+r) >> 1;
buildtree(lson);
buildtree(rson);
PushUp(id);
}
void Update(int id,int pos,int ope)
{
if(st[id].l == st[id].r)
{
st[id].num += ope;
return;
}
if(st[id<<1].r >= pos) Update(id<<1,pos,ope);
else Update(id<<1|1,pos,ope);
PushUp(id);
}
int query(int id,int l,int r)
{
if(st[id].l == l && st[id].r == r)
{
return st[id].num;
}
if(st[id<<1].r >= r)
{
return query(id<<1,l,r);
}
if(st[id<<1|1].l <= l)
{
return query(id<<1|1,l,r);
}
return query(id<<1,l,st[id<<1].r) + query(id<<1|1,st[id<<1|1].l,r);
}
int main()
{
//freopen("in.txt","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
for(int i = 1;i <= n;i++)
{
scanf("%d",&X[i]);
}
memcpy(XX,X,sizeof(X));
sort(X+1,X+n+1);
buildtree(1,1,n);
for(int i = 0;i < m;i++)
{
scanf("%d%d%d",&que[i].from,&que[i].to,&que[i].k);
que[i].id = i+1;
}
sort(que,que+m,cmp);
int l = 1,r = n;
for(int i = 1;i <= n;i++)
{
int pos = lower_bound(X+1,X+n+1,XX[i]) - X;
Update(1,pos,1);
}
for(int i = 0;i < m;i++)
{
int u = que[i].from,v = que[i].to;
if(r >= u)
{
if(l < que[i].from)
{
for(int j = l;j < que[i].from;j++)
{
int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
Update(1,pos,-1);
}
}
if(r > que[i].to)
{
for(int j = que[i].to + 1;j <= r;j++)
{
int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
Update(1,pos,-1);
}
}
else if(r < que[i].to)
{
for(int j = r+1;j <= que[i].to;j++)
{
int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
Update(1,pos,1);
}
}
}
else
{
for(int j = l;j <= r;j++)
{
int pos = lower_bound(X+1,X+n+1,XX[j])-X;
Update(1,pos,-1);
}
for(int j = que[i].from;j <= que[i].to;j++)
{
int pos = lower_bound(X+1,X+n+1,XX[j])-X;
Update(1,pos,1);
}
}
//树已经维护好了,接下来就是二分查找的过程。
int ll = 1,rr = n;
int k = que[i].k;
while(ll < rr)
{
int mid = (ll + rr) >> 1;
if(query(1,1,mid) >= k) rr = mid;
else ll = mid + 1;
}
Ans[que[i].id] = X[ll];
l = que[i].from,r = que[i].to;
}
for(int i = 1;i <= m;i++)
{
printf("%d\n",Ans[i]);
}
}
return 0;
}
接下来是树状数组。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 100080
int c[maxn];
int X[maxn],XX[maxn],Ans[maxn];
int lowbit(int x)
{
return x&(-x);
}
struct Que
{
int from,to,k,id;
}que[maxn];
bool cmp(Que a,Que b)
{
if(a.from < b.from) return 1;
else if(a.from > b.from) return 0;
else return a.to < b.to;
}
void update(int x,int add)
{
while(x < maxn)
{
c[x]+=add;
x+=lowbit(x);
}
}
int getsum(int x)
{
int sum = 0;
while(x > 0)
{
sum += c[x];
x -= lowbit(x);
}
return sum;
}
int main()
{
//freopen("in.txt","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
for(int i = 1;i <= n;i++) scanf("%d",&X[i]);
for(int i = 0;i < m;i++)
{
scanf("%d%d%d",&que[i].from,&que[i].to,&que[i].k);
que[i].id = i + 1;
}
sort(que,que+m,cmp);
memset(c,0,sizeof(c));
memcpy(XX,X,sizeof(X));
sort(X+1,X+n+1);
for(int i = 1;i <= n;i++)
{
int pos = lower_bound(X+1,X+n+1,XX[i]) - X;
update(pos,1);
}
int l = 1,r = n;
for(int i = 0;i < m;i++)
{
int u = que[i].from,v = que[i].to;
if(r >= u)
{
if(l < que[i].from)
{
for(int j = l;j < que[i].from;j++)
{
int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
update(pos,-1);
}
}
if(r > que[i].to)
{
for(int j = que[i].to + 1;j <= r;j++)
{
int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
update(pos,-1);
}
}
else if(r < que[i].to)
{
for(int j = r+1;j <= que[i].to;j++)
{
int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
update(pos,1);
}
}
}
else
{
for(int j = l;j <= r;j++)
{
int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
update(pos,-1);
}
for(int j = que[i].from;j <= que[i].to;j++)
{
int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
update(pos,1);
}
}
int ll = 1,rr = n;
int k = que[i].k;
while(ll < rr)
{
int mid = (ll + rr) >> 1;
if(getsum(mid) >= k) rr = mid;
else ll = mid + 1;
}
Ans[que[i].id] = X[ll];
l = que[i].from,r = que[i].to;
}
for(int i = 1;i <= m;i++) printf("%d\n",Ans[i]);
}
return 0;
}
接下来是一点都不SB的SB树:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define nil 0
#define maxn 200080
int key[maxn],Left[maxn],Right[maxn],Size[maxn];
int A[maxn],Ans[maxn];
int root,node;
int record;//This is used for the commented Delete
struct Que
{
int from,to,k,id;
}que[maxn];
bool cmp(Que a,Que b)
{
if(a.from < b.from) return 1;
else if(a.from > b.from) return 0;
else return a.to < b.to;
}
inline void Left_Rotate(int & x)
{
int k = Right[x];
Right[x] = Left[k];
Left[k] = x;
Size[k] = Size[x];
Size[x] = Size[Left[x]] + Size[Right[x]] + 1;
x = k;
}
inline void Right_Rotate(int & y)
{
int k = Left[y];
Left[y] = Right[k];
Right[k] = y;
Size[k] = Size[y];
Size[y] = Size[Left[y]] + Size[Right[y]] + 1;
y = k;
}
void Maintain(int & T,bool flag);
void Insert(int & T,int v)
{
if(T == nil)
{
key[T = ++node] = v;
Size[T] = 1;
Left[T] = Right[T] = nil;
}
else
{
Size[T]++;
if(v < key[T]) Insert(Left[T],v);
else
Insert(Right[T],v);大于等于就在右边添加。
Maintain(T,v >= key[T]);
}
}
int Delete(int & T,int v)///Delete函数我不是很清楚。
{
if(!T) return 0;
Size[T]--;
if( (v == key[T]) || (v < key[T] && Left[T] == nil) ||
(v > key[T] && Right[T] == nil) )
{
if(Left[T] == nil || Right[T] == nil)如果只有单支子系,直接用儿子代替他就行了。
{
int p = T;
T = Left[T] + Right[T];
return p;
}
else
{
//int p = Delete(Left[T],key[T] + 1);
int p = Delete(Left[T],v+1);
key[T] = key[p];///否则的话,用左支的最大值来替代这个删除点。
return p;
}
}
else
{
if(v < key[T])
return Delete(Left[T],v);
else return Delete(Right[T],v);
}
}
void Maintain(int & T,bool flag)
{
if(flag == false)
{
if(Size[Left[Left[T]]] > Size[Right[T]])
Right_Rotate(T);
else if(Size[Right[Left[T]]] > Size[Right[T]])
{
Left_Rotate(Left[T]);
Right_Rotate(T);
}
else return;
}
else
{
if(Size[Right[Right[T]]] > Size[Left[T]])
Left_Rotate(T);
else if(Size[Left[Right[T]]] > Size[Left[T]])
{
Right_Rotate(Right[T]);
Left_Rotate(T);
}
else return;
}
Maintain(Left[T],false);
Maintain(Right[T],true);
Maintain(T,false);
Maintain(T,true);
}
int Search(int x,int k)///寻找=k的那个数
{
if(x == nil || k == key[x])
return x;
if(k < key[x])
return Search(Left[x],k);
else return Search(Right[x],k);
}
int Select(int T,int k)///选择第k小的数
{
int r = 1 + Size[Left[T]];
if(k == r)
return key[T];
else if(k < r)
return Select(Left[T],k);
else return Select(Right[T],k - r);
}
int Succ(int T,int k)///找后继
{
if(T == nil)
return k;
if(key[T] <= k)
return Succ(Right[T],k);
else
{
int r = Succ(Left[T],k);
if(r == k) return key[T];
else return r;
}
}
int Pred(int T,int k)///找前驱
{
if(T == nil)
return k;
if(key[T] >= k)
return Pred(Left[T],k);
else
{
int r = Pred(Right[T],k);
if(r == k)
return key[T];
else return r;
}
}
int Rank(int T,int k)///k在这颗树中排第几大
{
if(T == nil) return 1;
if(key[T] >= k) return Rank(Left[T],k);
else return Size[Left[T]] + Rank(Right[T],k) + 1;
}
int main()
{
//freopen("in.txt","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
for(int i = 1;i <= n;i++) scanf("%d",&A[i]);
for(int i = 0;i < m;i++)
{
int u,v,k; scanf("%d%d%d",&u,&v,&k);
que[i].from = u,que[i].to = v,que[i].k = k,que[i].id = i+1;
}
memset(Size,0,sizeof(Size));
sort(que,que+m,cmp);
root = node = 0;
for(int i = 1;i <= n;i++) Insert(root,A[i]);
int l = 1,r = n;
for(int i = 0;i < m;i++)
{
int u = que[i].from,v = que[i].to,k = que[i].k;
if(r >= u)
{
if(l < u)
{
for(int j = l;j < u;j++) Delete(root,A[j]);
}
if(r < v)
{
for(int j = r+1;j <= v;j++) Insert(root,A[j]);
}
else if(r > v)
{
for(int j = v+1;j <= r;j++) Delete(root,A[j]);
}
}
else
{
for(int j = l;j <= r;j++) Delete(root,A[j]);
for(int j = u;j <= v;j++) Insert(root,A[j]);
}
Ans[que[i].id] = Select(root,k);
l = u,r = v;
}
for(int i = 1;i <= m;i++) printf("%d\n",Ans[i]);
}
return 0;
}
接下来是专门解决区间第K小的主席树:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <string>
#include <string>
using namespace std;
#define maxn 100080
#define maxm 5600800
int T[maxn],key[maxn],a[maxn];
int c[maxm],lson[maxm],rson[maxm];
int n,m,tot;
void Hash_init()
{
tot = 0;
for(int i = 1;i <= n;i++) a[i] = key[i];
sort(key+1,key+n+1);
}
int Hash(int k)
{
return lower_bound(key+1,key+n+1,k) - key;
}
int build(int l,int r)
{
int root = tot++;
c[root] = 0;
if(l != r)
{
int mid = (l+r) >> 1;
lson[root] = build(l,mid);
rson[root] = build(mid+1,r);
}
return root;
}
int Update(int root,int pos,int val)
{
int newnode = tot++,tmp = newnode;
c[newnode] = c[root] + val;
int l = 1,r = n;
while(l < r)
{
int mid = (l+r) >> 1;
if(pos <= mid)
{
lson[newnode] = tot++; rson[newnode] = rson[root];
newnode = lson[newnode]; root = lson[root];
r = mid;
}
else
{
rson[newnode] = tot++;
lson[newnode] = lson[root];
newnode = rson[newnode];
root = rson[root];
l = mid + 1;
}
c[newnode] = c[root] + val;
}
return tmp;
}
int query(int left_root,int right_root,int k)
{
int l = 1,r = n;
while(l < r)
{
int mid = (l+r) >> 1;
if(c[lson[left_root]] - c[lson[right_root]] >= k)
{
r = mid;
left_root = lson[left_root];
right_root = lson[right_root];
}
else
{
l = mid + 1;
k -= c[lson[left_root]] - c[lson[right_root]];
left_root = rson[left_root];
right_root = rson[right_root];
}
}
return l;
}
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
for(int i = 1;i <= n;i++) scanf("%d",&key[i]);
Hash_init();
T[n+1] = build(1,n);
for(int i = n;i >= 1;i--)
{
int pos = Hash(a[i]);
T[i] = Update(T[i+1],pos,1);
}
while(m--)
{
int u,v,k; scanf("%d%d%d",&u,&v,&k);
printf("%d\n",key[query(T[u],T[v+1],k)]);
}
}
return 0;
}