[HihoCoder1169]猜单词
题目大意:
给你一个数列,问区间[l,r]内与k最接近的数与k的差是多少。
思路:
将数列中的数和询问的数先从小到大排序,
从小到大枚举每个数,如果是数列上的,就加到线段树中,
如果是询问中的,就在线段树上查找区间最大值,
这样就找到了区间中小于等于这个数的最大值。
反过来也一样。
一个最大值、一个最小值,对于询问的数作差,取min即可。
比原来的主席树算法不知道妙到哪里去了。
主席树加了离散化以后应该能过,不过我的程序一直没过,然而虞皓翔同样是主席树的程序可以随便过。
大概是我写得比较烂吧。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 #include<algorithm> 5 #include<functional> 6 7 inline int getint() { 8 register char ch; 9 while(!isdigit(ch=getchar())); 10 register int x=ch^'0'; 11 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 12 return x; 13 } 14 15 const int inf=0x7fffffff; 16 const int N=200001; 17 18 struct Num { 19 int val,pos,l,r,id; 20 bool operator < (const Num &another) const { 21 if(val<another.val) return true; 22 if(val>another.val) return false; 23 return pos; 24 } 25 bool operator > (const Num &another) const { 26 if(val>another.val) return true; 27 if(val<another.val) return false; 28 return pos; 29 } 30 }; 31 std::vector<Num> v; 32 33 class SegmentTree { 34 #define _left <<1 35 #define _right <<1|1 36 private: 37 int val[N<<2]; 38 void push_up(const int &p,const bool &cmp) { 39 val[p]=cmp?std::max(val[p _left],val[p _right]):std::min(val[p _left],val[p _right]); 40 } 41 public: 42 void reset(const int &x) { 43 std::fill(&val[0],&val[N<<2],x); 44 } 45 void modify(const int &p,const int &b,const int &e,const int &x,const int &v,const bool &cmp) { 46 if(b==e) { 47 val[p]=v; 48 return; 49 } 50 const int mid=(b+e)>>1; 51 if(x<=mid) modify(p _left,b,mid,x,v,cmp); 52 if(x>mid) modify(p _right,mid+1,e,x,v,cmp); 53 push_up(p,cmp); 54 } 55 int query(const int &p,const int &b,const int &e,const int &l,const int &r,const bool &cmp) { 56 if(b==l&&e==r) { 57 return val[p]; 58 } 59 const int mid=(b+e)>>1; 60 int ret=cmp?-1:inf; 61 if(l<=mid) ret=cmp?std::max(ret,query(p _left,b,mid,l,std::min(mid,r),cmp)):std::min(ret,query(p _left,b,mid,l,std::min(mid,r),cmp)); 62 if(r>mid) ret=cmp?std::max(ret,query(p _right,mid+1,e,std::max(mid+1,l),r,cmp)):std::min(ret,query(p _right,mid+1,e,std::max(mid+1,l),r,cmp)); 63 return ret; 64 } 65 #undef _left 66 #undef _right 67 }; 68 SegmentTree t; 69 70 int ans[N]; 71 72 int main() { 73 int T=getint(); 74 for(register int i=1;i<=T;i++) { 75 printf("Case #%d:\n",i); 76 const int n=getint(),q=getint(); 77 v.clear(); 78 for(register int i=1;i<=n;i++) { 79 v.push_back((Num){getint(),i,0,0,0}); 80 } 81 for(register int i=0;i<q;i++) { 82 const int l=getint(),r=getint(),k=getint(); 83 v.push_back((Num){k,0,l,r,i}); 84 } 85 std::fill(&ans[0],&ans[q],inf); 86 t.reset(-1); 87 std::sort(v.begin(),v.end(),std::less<Num>()); 88 for(register std::vector<Num>::iterator it=v.begin();it!=v.end();it++) { 89 if(it->pos) { 90 t.modify(1,1,n,it->pos,it->val,true); 91 } else { 92 const int tmp=t.query(1,1,n,it->l,it->r,true); 93 if(tmp!=-1) ans[it->id]=std::min(ans[it->id],std::abs(tmp-it->val)); 94 } 95 } 96 t.reset(inf); 97 std::sort(v.begin(),v.end(),std::greater<Num>()); 98 for(register std::vector<Num>::iterator it=v.begin();it!=v.end();it++) { 99 if(it->pos) { 100 t.modify(1,1,n,it->pos,it->val,false); 101 } else { 102 const int tmp=t.query(1,1,n,it->l,it->r,false); 103 if(tmp!=inf) ans[it->id]=std::min(ans[it->id],std::abs(tmp-it->val)); 104 } 105 } 106 for(register int i=0;i<q;i++) { 107 printf("%d\n",ans[i]); 108 } 109 } 110 return 0; 111 }
原来也写过一个主席树的写法,然而复杂度不是很优秀,一直过不了。
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int inf=0x7fffffff; 12 const int N=200001; 13 int size; 14 class FotileTree { 15 private: 16 struct Node { 17 int left,right,val; 18 }; 19 Node nd[N*40]; 20 int sz,newNode(const int &p) { 21 sz++; 22 nd[sz]=nd[p]; 23 return sz; 24 } 25 public: 26 int root[N]; 27 void reset() { 28 sz=0; 29 } 30 int modify(const int &p,const int &b,const int &e,const int &x) { 31 int new_p=newNode(p); 32 nd[new_p].val++; 33 if(b==e) return new_p; 34 const int mid=(b+e)>>1; 35 if(x<=mid) nd[new_p].left=modify(nd[p].left,b,mid,x); 36 if(x>mid) nd[new_p].right=modify(nd[p].right,mid+1,e,x); 37 return new_p; 38 } 39 int queryleq(const int &p1,const int &p2,const int &b,const int &e,const int &x) const { 40 if(!(nd[p2].val-nd[p1].val)) return size-1; 41 if(b==e) return e; 42 const int mid=(b+e)>>1; 43 if(x<=mid) return queryleq(nd[p1].left,nd[p2].left,b,mid,x); 44 int ret; 45 if((ret=queryleq(nd[p1].right,nd[p2].right,mid+1,e,x))!=size-1) return ret; 46 if((ret=queryleq(nd[p1].left,nd[p2].left,b,mid,x))!=size-1) return ret; 47 return size-1; 48 } 49 int querygeq(const int &p1,const int &p2,const int &b,const int &e,const int &x) const { 50 if(!(nd[p2].val-nd[p1].val)) return size-1; 51 if(b==e) return b; 52 const int mid=(b+e)>>1; 53 if(x>mid) return querygeq(nd[p1].right,nd[p2].right,mid+1,e,x); 54 int ret; 55 if((ret=querygeq(nd[p1].left,nd[p2].left,b,mid,x))!=size-1) return ret; 56 if((ret=querygeq(nd[p1].right,nd[p2].right,mid+1,e,x))!=size-1) return ret; 57 return size-1; 58 } 59 }; 60 FotileTree t; 61 int a[N],l[N],r[N],x[N],b[N+N]; 62 int main() { 63 int T=getint(); 64 for(register int i=1;i<=T;i++) { 65 printf("Case #%d:\n",i); 66 const int n=getint(),q=getint(); 67 b[0]=inf; 68 for(register int i=1;i<=n;i++) { 69 b[i]=a[i]=getint(); 70 } 71 for(register int i=1;i<=q;i++) { 72 l[i]=getint(); 73 r[i]=getint(); 74 b[n+i]=x[i]=getint(); 75 } 76 std::sort(&b[0],&b[n+q+1]); 77 size=std::unique(&b[0],&b[n+q+1])-b; 78 for(register int i=1;i<=n;i++) { 79 const int id=std::lower_bound(&b[0],&b[size],a[i])-b; 80 t.root[i]=t.modify(t.root[i-1],0,size-1,id); 81 } 82 for(register int i=1;i<=q;i++) { 83 const int id=std::lower_bound(&b[0],&b[size],x[i])-b; 84 const int leq=b[t.queryleq(t.root[l[i]-1],t.root[r[i]],0,size-1,id)]; 85 const int geq=b[t.querygeq(t.root[l[i]-1],t.root[r[i]],0,size-1,id)]; 86 printf("%d\n",std::min(std::abs(x[i]-leq),std::abs(x[i]-geq))); 87 } 88 } 89 return 0; 90 }