http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3633
两种解法:
自己的解法是,因为当时考虑到开visit数组10的31方太大了,所以首先将给定的数离散化,然后对于在范围内的每一个数和他所在的数组中的下标连边。
询问的时候,遍历查询范围,对于每一个数,如果这个数所连的边中下标有在这个数之前且在查询范围内的那么输出这个数就可以了。
**********开始的时候ok搞成了小写,wa到吐血。。。。
#include<iostream> #include<string.h> #include<algorithm> #include<vector> #include<stdio.h> #include<stdlib.h> #define maxn 500100 using namespace std; struct node0 { long long key; int id; }node[maxn]; vector<int>line[maxn]; int n; int m; long long number[maxn]; bool cmp1(struct node0 a,struct node0 b) { return a.key<b.key; } bool cmp2(struct node0 a,struct node0 b) { return a.id<b.id; } int main() { long long max; while(cin>>n) { memset(number,0,sizeof(number)); memset(node,0,sizeof(node)); for(int i=0;i<=n;i++) line[i].clear(); for(int i=0;i<n;i++) { cin>>node[i].key; number[i]=node[i].key; node[i].id=i; } sort(node,node+n,cmp1);//按照从小大大排序
//离散化 int temp=node[0].key; node[0].key=0; line[0].push_back(node[0].id); for(int i=1;i<n;i++) { if(node[i].key==temp) node[i].key=node[i-1].key,line[node[i].key].push_back(node[i].id);//连边 else temp=node[i].key,node[i].key=node[i-1].key+1,line[node[i].key].push_back(node[i].id);//连边 } sort(node,node+n,cmp2);//按照下标排序。 cin>>m; while(m--) { int st,en; int flage=0; cin>>st>>en; int id; for(int i=en-1;i>=st-1;i--) { for(int j=0;j<line[node[i].key].size();j++) { if(line[node[i].key][j]>=i+1&&line[node[i].key][j]<=en-1)//访问 if(line[node[i].key][j]!=i) { flage=1;id=i;break; } } if(flage)break; } if(flage) cout<<number[id]<<endl; else cout<<"OK"<<endl; } cout<<endl; } return 0; }
网上流传的做法是线段树,想了下也是,自己当时没有想到,对于每一个取得在这个数之前的和他相等的那个数的下标。在线段树中加入maxd属性,表示的是当前区间的所有数中,有一个数,和这个数的相等的且在这个数之前的那个下标比该区间的其他数的这个属性都大。
然后就可以了,要判断返回的下标是不是在区间内
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include <vector> #include<map> #define maxn 500100 using namespace std; int visit[100]; struct node0 { int l; int r; int maxd; }node[maxn]; int dis[maxn]; int number[maxn]; void build(int root,int l,int r) { node[root].l=l; node[root].r=r; if(l==r) { node[root].maxd=dis[l]; return ; } int mid=(l+r)>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r); node[root].maxd=max(node[root<<1].maxd,node[root<<1|1].maxd); return ; } int query(int root,int l,int r) { //cout<<root<<" "<<node[root].l<<" "<<node[root].r<<" "<<node[root].maxd<<endl; if(node[root].l==l&&node[root].r==r) return node[root].maxd; //if(l==r)return 0; int mid=(node[root].l+node[root].r)>>1; if(r<=mid) return query(root<<1,l,r); else if(l>mid) return query(root<<1|1,l,r); else { return max(query(root<<1,l,mid),query(root<<1|1,mid+1,r)); } } void output(int root) { if(!visit[root]); cout<<node[root].l<<" "<<node[root].r<<" "<<node[root].maxd<<" "<<root<<endl;; visit[root]=1; if(node[root].l==node[root].r)return ; output(root<<1); output(root<<1|1); } int main() { int n,m; int st,en; while(cin>>n) { map<long long,int>v; for(int i=1;i<=n;i++) { cin>>number[i]; dis[i]=v[number[i]]; v[number[i]]=i; } build(1,1,n); // output(1); cin>>m; while(m--) { cin>>st>>en; int temp=query(1,st,en); if(temp>=st&&temp<=en) cout<<number[temp]<<endl; else cout<<"ok"<<endl; } cout<<endl; } return 0; }
线段树的还是比自己的要快