标签:
好神啊好神啊.....
大概就是,对于一个询问,我们可以二分答案求出结果的话......
那么对于一大堆询问,我们一起二分它们的答案......
然后,我们通过某种简化的判定条件来决定询问应该被分到左边还是右边.
把当前处理的询问扫一遍,求出应该往左递归的询问和往右递归的询问. 然后把左边的询问堆到一起,往下传.
注意我们可能需要维护一些附加信息.....看题...
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 }
找个简单题练手.......
看哈,我们二分操作不是要对每个询问判断:在区间中,有多少个数比mid大嘛?
那么我们把这个区间里面所有的数扫一遍,统计比mid大的数的个数.
但是多个询问不允许我们直接扫.
论文给出的解决方法是,
求出所有能力值属于当前二分到的左权值区间(l,mid)的狮子的下标.
对其排序并用询问的区间进行二分. upper_bound-lower_bound就行了.
这样可以用 $log$ 级别的时间求出每个区间的比mid大的数的个数.
运用整体二分算法的关键就在于此. 我们加速的方式,就是快速求出一堆询问的二分判定.
简单地说,就是,给你一堆询问,问你,哪些询问的结果应该被分到左区间? 哪些在右区间?
解决这个问题的复杂度如果为 $f(k)$ ,那么算法总的复杂度为 $f(n)\log{v}$ .
复杂度是 $O(\log{v} \log{n}( m+n))$ ,比可持久化线段树慢三分之一.
神奇的网站.....神奇的题库.....
标签:
原文地址:http://www.cnblogs.com/DragoonKiller/p/4564447.html