POJ2761--Feed the dogs
2013-11-14 21:32
621 查看
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.
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.
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
Sample Output
32
神题啊,线段树,树状数组,Treap,SBT,Splay都可以做。
接下来是线段树做法:
接下来是树状数组。
接下来是一点都不SB的SB树:
接下来是专门解决区间第K小的主席树:
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.
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.
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; }
相关文章推荐
- 求区间第K小值的两种解法:POJ2761
- html中接受用户输入的form表单定义方式
- Andorid存储方式----SharedPreferences存储
- Andorid存储方式----SharedPreferences存储
- 第一次自己写jquery图片延迟加载插件,不通用,但修改一下还是可以使用到很多页面上的
- js获取Listbox选择的值
- HTML入门教程
- javascript 的一些理解和随笔
- css 中字体大小
- Undefined reference to” 的处理
- 解决IE6-IE8 Js代码不执行问题
- JScrollPane的使用
- 简单的表单验证--js,jsp,jquery,java,mysql(前台和后台验证)(
- jQuery和Ajax
- jquery的each()使用
- 读《the facebook effect》
- 关于我在做一些项目时候帮助过我的一些资料库的链接
- js-获取自定义属性
- [置顶] Jquery学习总结(二) jquery选择器详解
- js使用url传参servelet乱码解决