码迷,mamicode.com
首页 > 其他好文 > 详细

二分法

时间:2015-06-09 21:43:54      阅读:110      评论:0      收藏:0      [点我收藏+]

标签:

好神啊好神啊.....

大概就是,对于一个询问,我们可以二分答案求出结果的话......

那么对于一大堆询问,我们一起二分它们的答案......

然后,我们通过某种简化的判定条件来决定询问应该被分到左边还是右边.

把当前处理的询问扫一遍,求出应该往左递归的询问和往右递归的询问. 然后把左边的询问堆到一起,往下传.

注意我们可能需要维护一些附加信息.....看题...

 

AC VIJOS 1081 野生动物园

技术分享
  1 #include <cstdio>
  2 #include <fstream>
  3 #include <iostream>
  4  
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cmath>
  9  
 10 #include <queue>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <stack>
 15 #include <list>
 16  
 17 typedef unsigned int uint;
 18 typedef long long int ll;
 19 typedef unsigned long long int ull;
 20 typedef double db;
 21  
 22 using namespace std;
 23  
 24 inline int getint()
 25 {
 26     int res=0;
 27     char c=getchar();
 28     bool mi=false;
 29     while(c<0 || c>9) mi=(c==-),c=getchar();
 30     while(0<=c && c<=9) res=res*10+c-0,c=getchar();
 31     return mi ? -res : res;
 32 }
 33 inline ll getll()
 34 {
 35     ll res=0;
 36     char c=getchar();
 37     bool mi=false;
 38     while(c<0 || c>9) mi=(c==-),c=getchar();
 39     while(0<=c && c<=9) res=res*10+c-0,c=getchar();
 40     return mi ? -res : res;
 41 }
 42 
 43 //==============================================================================
 44 //==============================================================================
 45 //==============================================================================
 46 //==============================================================================
 47 
 48 const int INF=(1<<30)-1;
 49 
 50 int n,m;
 51 
 52 struct query
 53 { int l,r,k,res; int id; };
 54 query op[50050];
 55 bool cmp(const query&a,const query&b)
 56 { return a.id < b.id; }
 57 
 58 int a[100050];
 59 int loc[100050];
 60 int cnt[100050];
 61     
 62 void DC(query*q,int qcnt,int*p,int pcnt,int l,int r)
 63 {
 64     if(qcnt==0) return ;
 65     if(l==r) { for(int i=0;i<qcnt;i++) q[i].res=l; return ; }
 66     
 67     int mid=(l+r)>>1;
 68     
 69     //solve. count amount of number larger than s
 70     // for each operation in Q.
 71     
 72     //pre process for count.
 73     int tot=0;
 74     for(int i=0;i<pcnt;i++) 
 75     if(a[p[i]]<=mid) loc[tot++]=p[i];
 76     sort(loc,loc+tot);
 77     loc[tot++]=INF;
 78     
 79     //count.
 80     for(int i=0;i<qcnt;i++)
 81     cnt[i]=int(upper_bound(loc,loc+tot,q[i].r)-lower_bound(loc,loc+tot,q[i].l));
 82     
 83     int vt=0;
 84     int qt=0; //these are the COUNTERs
 85     for(int i=0;i<pcnt;i++) if(a[p[i]]<=mid) swap(p[vt],p[i]),vt++;
 86     for(int i=0;i<qcnt;i++) 
 87         if(q[i].k<=cnt[i]) swap(q[i],q[qt]),qt++;
 88         else q[i].k-=cnt[i];
 89     
 90     DC(q,qt,p,vt,l,mid);
 91     DC(q+qt,qcnt-qt,p+vt,pcnt-vt,mid+1,r);
 92 }
 93 
 94 int preloc[100050];
 95 
 96 int main()
 97 {
 98     n=getint();
 99     m=getint();
100     int miv=INF;
101     int mxv=-INF;
102     for(int i=0;i<n;i++)
103     a[i]=getint(),mxv=max(mxv,a[i]),miv=min(miv,a[i]);
104     for(int i=0;i<m;i++)
105     {
106         int l=getint()-1;
107         int r=getint()-1;
108         int k=getint();
109         op[i]=(query){l,r,k,0,i};
110     }
111     
112     for(int i=0;i<n;i++) preloc[i]=i;
113     DC(op,m,preloc,n,miv,mxv);
114     
115     sort(op,op+m,cmp);
116     
117     for(int i=0;i<m;i++)
118     printf("%d\n",op[i].res);
119     
120     return 0;
121 }
View Code

找个简单题练手.......

看哈,我们二分操作不是要对每个询问判断:在区间中,有多少个数比mid大嘛?

那么我们把这个区间里面所有的数扫一遍,统计比mid大的数的个数.

但是多个询问不允许我们直接扫.

 

论文给出的解决方法是,

求出所有能力值属于当前二分到的权值区间(l,mid)的狮子的下标.

对其排序并用询问的区间进行二分. upper_bound-lower_bound就行了.

这样可以用 $log$ 级别的时间求出每个区间的比mid大的数的个数.

运用整体二分算法的关键就在于此. 我们加速的方式,就是快速求出一堆询问的二分判定.

简单地说,就是,给你一堆询问,问你,哪些询问的结果应该被分到左区间? 哪些在右区间?

解决这个问题的复杂度如果为 $f(k)$ ,那么算法总的复杂度为 $f(n)\log{v}$ .

 

 

 

复杂度是 $O(\log{v} \log{n}( m+n))$ ,比可持久化线段树慢三分之一.

 

 

 

 

 

 

 

http://main.edu.pl/en

 神奇的网站.....神奇的题库.....

 

二分法

标签:

原文地址:http://www.cnblogs.com/DragoonKiller/p/4564447.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!