该oj是qsc自己写的比赛,友情链接:http://qscoj.cn/
喵哈哈村的排队
发布时间: 2017年2月26日 16:13 最后更新: 2017年2月26日 16:14 时间限制: 1000ms 内存限制: 128M
有一堆喵哈哈村的村民们在排队,他们从队列的尾部开始标号,标号为1的村民站在最后面,标号为n的村民站在队列的最前面,而且每个村民都拥有一个智商值a[i]。
这些村民有时候会觉得不开心,因为他们觉得凭什么一个智商比他低的人,可以站在他的前面!现在对于每个村民,他们都想知道,在他前面,智商比他低,离他最远的距离是多少。
第一行n,表示有n只咸鱼
第二行n个整数,表示每个村民的智商值a[i].
n<=200000 1<=a[i]<=1000000000
对于每个村民,输出智商比他的,且离他最远的距离是多少,如果没有输出-1
复制
6 10 8 5 3 50 45
2 1 0 -1 0 -1
原本是水题来着,2333想七想八搞了个贪心+权值线段树+并查集,然后。。WA。贪心的策略根本不对好久才发现。最近真的是第K大做多了,思维同化。以下是WA代码给自己的提醒。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define clr(x) memset(x,0,sizeof(x)) 6 using namespace std; 7 struct segtree 8 { 9 int val,num,l,r; 10 }tree[1000010]; 11 int a[200010],num[200010],fa[200010],afront[200010],n,m,l,r,k,rnu; 12 void init(int i,int l,int r); 13 void update(int i,int num); 14 int query(int i,int num); 15 int findpos(int i,int big); 16 int findposd(int num,int l,int r); 17 int Find(int i); 18 int main() 19 { 20 int n; 21 while(scanf("%d",&n)!=EOF) 22 { 23 clr(tree); 24 clr(afront); 25 for(int i=1;i<=n;i++) 26 scanf("%d",&num[i]); 27 memcpy(a,num,sizeof(num)); 28 sort(a+1,a+n+1); 29 for(int i=0;i<=n;i++) 30 fa[i]=i; 31 rnu=unique(a+1,a+n+1)-a-1; 32 init(1,1,rnu); 33 for(int i=n;i>=1;i--) 34 { 35 k=query(1,num[i]); 36 if(k!=0) 37 { 38 l=findpos(1,k); 39 // printf("%d %d ",k,l); 40 fa[i]=Find(afront[l]); 41 } 42 afront[findposd(num[i],1,rnu)]=i; 43 update(1,num[i]); 44 } 45 for(int i=1;i<=n;i++) 46 { 47 if(num[Find(i)]!=num[i]) 48 printf("%d ",Find(i)-i-1); 49 else 50 printf("-1 "); 51 } 52 printf(" "); 53 } 54 return 0; 55 } 56 void init(int i,int l,int r) 57 { 58 tree[i].l=l; 59 tree[i].r=r; 60 tree[i].val=a[r]; 61 if(l==r) 62 return ; 63 int mid=(l+r)>>1; 64 init(i<<1,l,mid); 65 init((i<<1)|1,mid+1,r); 66 return ; 67 } 68 void update(int i,int num) 69 { 70 tree[i].num++; 71 if(tree[i].l==tree[i].r) 72 return ; 73 if(tree[i<<1].val>=num) 74 update(i<<1,num); 75 else 76 update((i<<1)|1,num); 77 return ; 78 } 79 int query(int i,int num) 80 { 81 if(tree[i].val<=num) 82 return tree[i].num; 83 else 84 { 85 if(tree[i<<1].val<num) 86 return query(i<<1,num)+query((i<<1)|1,num); 87 else 88 return query(i<<1,num); 89 } 90 } 91 int findpos(int i,int big) 92 { 93 if(tree[i].l==tree[i].r) 94 return tree[i].l; 95 if(tree[i<<1].num>=big) 96 return findpos(i<<1,big); 97 else 98 return findpos((i<<1)|1,big-tree[i<<1].num); 99 } 100 int findposd(int num,int l,int r) 101 { 102 if(l==r) 103 return l; 104 int mid=(l+r)>>1; 105 if(a[mid]>num) 106 return findposd(num,l,mid-1); 107 if(a[mid]<num) 108 return findposd(num,mid+1,r); 109 return mid; 110 } 111 int Find(int i) 112 { 113 if(fa[i]!=i) 114 fa[i]=Find(fa[i]); 115 return fa[i]; 116 }
一个无脑的做法:对于每个人进行二分,二分之后用线段树取区间最小值或者一个其他的数据结构去维护就好了。
但实际上有其他的做法:
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <algorithm> 5 #define MAX 200002 6 using namespace std; 7 8 int a[MAX],ans[MAX]; 9 vector<int> v,num; 10 11 int main() 12 { 13 int n; 14 while(~scanf("%d",&n)){ 15 for(int i=0;i<n;i++) scanf("%d",&a[i]); 16 v.clear(); 17 num.clear(); 18 for(int i=n-1;i>=0;i--){ 19 if(v.size()==0 || v.back()>=a[i]){ 20 v.push_back(a[i]); num.push_back(i); 21 ans[i]=-1; 22 }else{ 23 int j = (lower_bound(v.rbegin(),v.rend(),a[i]) - v.rbegin()); 24 j = (int)v.size() - j - 1; 25 ans[i] = num[j+1] - i - 1; 26 } 27 } 28 for(int i=0;i<n;i++){ 29 if(i) printf(" "); 30 printf("%d",ans[i]); 31 } 32 printf(" "); 33 } 34 return 0; 35 }