二分与分治
好神啊好神啊.....
大概就是,对于一个询问,我们可以二分答案求出结果的话......
那么对于一大堆询问,我们一起二分它们的答案......
然后,我们通过某种简化的判定条件来决定询问应该被分到左边还是右边.
把当前处理的询问扫一遍,求出应该往左递归的询问和往右递归的询问. 然后把左边的询问堆到一起,往下传.
注意我们可能需要维护一些附加信息.....看题...
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))$ ,比可持久化线段树慢三分之一.
AC POI2011 Meteors
从这里看的题目和题解 http://victorwonder.is-programmer.com/posts/70210.html?utm_source=tuicool
讲得非常清楚..... 然后题目可以在下边这个网站交......
神奇的网站.....神奇的题库.....神奇的题目....
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 ll INF=((ll)1<<56)-1;
49
50
51 int n,m,k;
52
53
54 ll cty[305000]; //station belongs to
55 ll ask[305000]; //meteors asked for countries.
56
57 struct op
58 { int l,r; ll v; } M[305000];
59
60 struct edge { int in; edge*nxt; };
61 int ecnt=5000; edge*et;
62 edge*eds[305000];
63 void addedge(int a,int b)
64 {
65 if(ecnt==5000){ecnt=0;et=new edge[5000];}
66 et->in=b; et->nxt=eds[a]; eds[a]=et++; ecnt++;
67 }
68 #define FOREACH_SON(i,x) for(edge*i=eds[x];i;i=i->nxt)
69
70 int stp[305000];
71 int res[305000];
72
73 struct SegTree
74 {
75 ll tag[1205000]; //SegTree tags
76 int cl,cr; ll cv;
77 void Change(int x=1,int l=0,int r=m-1)
78 {
79 if(cl<=l && r<=cr) { tag[x]+=cv; return ; }
80 int mid=(l+r)>>1;
81 if(mid>=cl) Change(x<<1,l,mid);
82 if(mid<cr) Change(x<<1|1,mid+1,r);
83 }
84 ll Query(int p)
85 {
86 int x=1,l=0,r=m-1;
87 ll res=0;
88 while(l!=r)
89 {
90 res+=tag[x];
91 if(res>INF) break;
92 int mid=(l+r)>>1;
93 if(p<=mid) { x<<=1; r=mid; }
94 else { x=x<<1|1; l=mid+1; }
95 }
96 res+=tag[x];
97 return res;
98 }
99 }T;
100
101 ll dc[605000];
102 void DC(int*p,int pt,int l,int r)
103 {
104 if(l==r) { for(int i=0;i<pt;i++) res[p[i]]=l; return ; }
105
106 int mid=(l+r)>>1;
107
108 //brute force to deal with the querys.
109 for(int i=l;i<=mid;i++)
110 {
111 T.cv=M[i].v;
112
113 if(M[i].l<=M[i].r)
114 T.cl=M[i].l,T.cr=M[i].r,T.Change();
115 else
116 {
117 T.cl=M[i].l,T.cr=m-1,T.Change();
118 T.cl=0,T.cr=M[i].r,T.Change();
119 }
120 }
121
122 for(int i=0;i<pt;i++) FOREACH_SON(e,p[i]) //....what's the complexity?
123 { dc[p[i]]+=T.Query(e->in); if(dc[p[i]]>=ask[p[i]]) break; }
124
125 for(int i=l;i<=mid;i++)
126 {
127 T.cv=-M[i].v;
128
129 if(M[i].l<=M[i].r)
130 T.cl=M[i].l,T.cr=M[i].r,T.Change();
131 else
132 {
133 T.cl=M[i].l,T.cr=m-1,T.Change();
134 T.cl=0,T.cr=M[i].r,T.Change();
135 }
136 }
137
138 int nxp=0;
139 for(int i=0;i<pt;i++)
140 if(dc[p[i]]>=ask[p[i]]) swap(p[i],p[nxp++]);
141
142 for(int i=nxp;i<pt;i++)
143 ask[p[i]]-=dc[p[i]]; //this will not meet the breaks above.
144
145 for(int i=0;i<pt;i++)
146 dc[p[i]]=0; //reverse edit.
147
148 DC(p,nxp,l,mid);
149 DC(p+nxp,pt-nxp,mid+1,r);
150 }
151
152 int main()
153 {
154 n=getint(); //amount of countries
155 m=getint(); //amount of stations
156
157 for(int i=0;i<m;i++)
158 addedge(getint()-1,i); //set station i to country getint()-1;
159
160 for(int i=0;i<n;i++)
161 ask[i]=getint();
162
163 k=getint();
164 for(int i=0;i<k;i++)
165 {
166 M[i].l=getint()-1;
167 M[i].r=getint()-1;
168 M[i].v=getint();
169 }
170 M[k].l=0; M[k].r=m-1; M[k].v=INF; //to change all NIE into a solution.
171
172 for(int i=0;i<n;i++) stp[i]=i; //pointers assign.
173 DC(stp,n,0,k);
174
175 for(int i=0;i<n;i++)
176 if(res[i]==k) printf("NIE\n");
177 else printf("%d\n",res[i]+1);
178
179 return 0;
180 }
实现用线段树,时间复杂度(大概)为 $O(\log{v}\log{m}n)$
人家用树状数组比我快三倍TAT
如果对单个询问进行二分,那就是二分一下时间,设中间的时间为 $mid$ .
显然要对询问(就是每个国家的陨石收集量)进行统计. 直接暴力,对每组陨石使用线段树或者树状数组,
维护区间和,询问单点值(嗯没错,把当前国家的空间站枚举一遍做统计就好了).......
统计完以后,按照国家收集的陨石数量超过/不超过需求量,把国家分成左右两部分....
然后,清空统计用的数组.注意一定要反向修改.....不能直接memset.....
需要注意的地方....
1.呃........动态加边加点一定要记得计数器加意加二什么的....!!!!!!
2.我们在数组里边存的是当前考虑的国家的编号. 注意在我们的操作过程中要改变那个编号数组,所以统计数组绝对不能省掉编号!(就是说,程序中d[p[i]]不能被修改成d[i],如果不再附加数组记录一些信息的话.)
cdq分治
AC BZOJ 1492 NOI2007 Cash
故意不去掉注释....这个题写的我想死啊........
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 typedef long double ldb;
22
23 using namespace std;
24
25 inline int getint()
26 {
27 int res=0;
28 char c=getchar();
29 bool mi=false;
30 while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
31 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
32 return mi ? -res : res;
33 }
34 inline ll getll()
35 {
36 ll res=0;
37 char c=getchar();
38 bool mi=false;
39 while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
40 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
41 return mi ? -res : res;
42 }
43
44 //==============================================================================
45 //==============================================================================
46 //==============================================================================
47 //==============================================================================
48
49 inline double getdb()
50 { double x; scanf("%lf",&x); return x; }
51
52 struct point //also vector
53 {
54 ldb x,y; point(){} point(ldb a,ldb b):x(a),y(b){}
55 ldb operator*(point f) { return x*f.y-y*f.x; }
56 point operator-(point f) { return point(x-f.x,y-f.y); }
57 point operator()(point f) { return point(f.x-x,f.y-y); }
58 };
59
60 inline bool ConvexChange(point&a,point&s1,point&s2)
61 //Should s1 be thrown from convex when I add a new point a?
62 { return s1(a)*s2(a)<=0.0; }
63
64 inline bool SlopeBetter(point&a,point&b,ldb k)
65 //Is a better than b when slope is k?
66 { return a.y-b.y >= k*(a.x-b.x); }
67
68 bool cmpdec(const ldb&a,const ldb&b)
69 { return a>=b; }
70
71 ldb d[105000];
72 ldb A[105000];
73 ldb B[105000];
74 ldb R[105000];
75
76 ldb X[105000];
77 ldb Y[105000];
78 ldb K[105000];
79 bool kcmp(const int&a,const int&b)
80 { return K[a]>=K[b]; }
81
82 point s[105000]; int st;
83
84 int h[105000]; //pointers for increasing slope.
85 int q[105000]; //merge sort auxiliary array.
86 int p[105000]; //pointers for increasing x coordinate.
87 void DC(int l,int r)
88 {
89 if(l==r)
90 {
91 d[l]=max(d[l-1],d[l]);
92 Y[l]=d[l]/(R[l]*A[l]+B[l]);
93 X[l]=Y[l]*R[l];
94 //printf("solved: %d %.4f %.4f %.4f\n",l,(db)d[l],(db)X[l],(db)Y[l]);
95 return ;
96 }
97 int mid=(l+r)>>1;
98
99 //divide h into two parts.
100 //then throw the left part to the left DC.
101 //and use right part for this function.
102 //and throw right part to the right DC.
103 //printf("[%d,%d]%d h(o):",l,r,mid); for(int i=l;i<=r;i++) printf("%d ",h[i]); printf("\n");
104
105 int p1=l,p2=mid+1;
106 for(int i=l;i<=r;i++)
107 if(h[i]<=mid) q[p1++]=h[i]; else q[p2++]=h[i];
108 memcpy(h+l,q+l,sizeof(int)*(r-l+1));
109
110 //printf("[%d,%d]%d h(d):",l,r,mid); for(int i=l;i<=r;i++) printf("%d ",h[i]); printf("\n");
111
112 DC(l,mid); //this will set queries in [l,mid] to correct ans.
113
114 //build convex.
115 st=0;
116 s[st++]=point(0,0); //nothing to transfer.?
117 for(int i=l;i<=mid;i++)
118 {
119 point c(X[p[i]],Y[p[i]]);
120 //printf("coordinate of %d is (%.4f,%.4f)\n",p[i],(db)X[p[i]],(db)Y[p[i]]);
121 while(st>1 && ConvexChange(c,s[st-1],s[st-2])) st--;
122 s[st++]=c;
123 }
124
125 //printf("Final Convex: ");for(int i=0;i<st;i++) printf("(%.4f,%.4f)",(db)s[i].x,(db)s[i].y); printf("\n");
126
127 //set queries in [mid+1,r] an answer.
128 int t=0;
129 //printf("h for trans: ");for(int i=mid+1;i<=r;i++) printf("%.4f ",(db)K[h[i]]); printf("\n");
130 //printf("[%d,%d] h for trans: ",l,r);for(int i=mid+1;i<=r;i++) printf("%d ",h[i]); printf("\n");
131 for(int i=mid+1;i<=r;i++)
132 {
133 int x=h[i];
134 //printf("%.4f ",(db)K[x]);
135 ldb k=K[x]; //notice that we should set K monotone decreasing.
136 while(t<st-1 && SlopeBetter(s[t+1],s[t],k)) t++;
137 d[x]=max(d[x],A[x]*s[t].x+B[x]*s[t].y);
138 //printf("update %.4f %.4f for %d\n",(db)s[t].x,(db)s[t].y,x);
139 }
140 //printf("end.\n");
141
142 DC(mid+1,r); //this will set queries in [mid+1,r] to correct ans.
143
144 //set array p.
145 //note that p is just for the next convex.
146 //it's not what we're doing divide and conquar on.
147 t=0;
148 p1=l,p2=mid+1;
149 while(p1<=mid && p2<=r)
150 if(X[p[p1]]<X[p[p2]]) q[t++]=p[p1++]; else q[t++]=p[p2++];
151 while(p1<=mid) q[t++]=p[p1++];
152 while(p2<=r) q[t++]=p[p2++];
153 memcpy(p+l,q,sizeof(int)*(r-l+1));
154
155 //printf("[%d,%d] p(d):",l,r); for(int i=l;i<=r;i++) printf("%d ",p[i]); printf("\n");
156 }
157
158
159 int n;
160
161 int main()
162 {
163 freopen("in.txt","r",stdin);
164 freopen("out.txt","w",stdout);
165
166 n=getint();
167 d[1]=d[0]=getdb();
168
169 for(int i=1;i<=n;i++)
170 A[i]=getdb(),
171 B[i]=getdb(),
172 R[i]=getdb();
173
174 for(int i=1;i<=n;i++)
175 K[i]=-(A[i]/B[i]);
176
177 for(int i=0;i<=n;i++)
178 h[i]=p[i]=i;
179
180 stable_sort(h+1,h+n+1,kcmp);
181
182 //for(int i=1;i<=n;i++) printf("%d A:%2.4f B:%2.4f R:%2.4f K:%2.4f\n",i,(db)A[i],(db)B[i],(db)R[i],(db)K[i]);
183 //for(int i=1;i<=n;i++) printf("%d %.4f\n",h[i],(db)K[h[i]]);
184
185 DC(1,n);
186
187 cout.precision(3);
188 cout<<fixed;
189 cout<<d[n]<<endl;
190
191 //for(int i=1;i<=n;i++) printf("resault of %d is %.4f\n",i,(db)d[i]);
192
193 return 0;
194 }
195
196 /*
197 5 1.00
198 12 8 3
199 13 9 2
200 13 9 2
201 13 10 2
202 13 8 3
203 */
对归并操作和凸壳维护太不熟了.........还有各种指针(包括保存下标的伪指针) o(╯□╰)o ......
听说有人被卡精度?于是我用了 long double ... 然而double也能A ......
不过BZOJ上的 long double 真的是12位=.=
还是把去掉注释的版本放上来吧.....
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 typedef long double ldb;
22
23 using namespace std;
24
25 inline int getint()
26 {
27 int res=0;
28 char c=getchar();
29 bool mi=false;
30 while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
31 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
32 return mi ? -res : res;
33 }
34 inline ll getll()
35 {
36 ll res=0;
37 char c=getchar();
38 bool mi=false;
39 while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
40 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
41 return mi ? -res : res;
42 }
43
44 //==============================================================================
45 //==============================================================================
46 //==============================================================================
47 //==============================================================================
48
49 inline double getdb()
50 { double x; scanf("%lf",&x); return x; }
51
52 struct point //also vector
53 {
54 ldb x,y; point(){} point(ldb a,ldb b):x(a),y(b){}
55 ldb operator*(point f) { return x*f.y-y*f.x; }
56 point operator-(point f) { return point(x-f.x,y-f.y); }
57 point operator()(point f) { return point(f.x-x,f.y-y); }
58 };
59
60 inline bool ConvexChange(point&a,point&s1,point&s2)
61 { return s1(a)*s2(a)<=0.0; }
62
63 inline bool SlopeBetter(point&a,point&b,ldb k)
64 { return a.y-b.y >= k*(a.x-b.x); }
65
66 bool cmpdec(const ldb&a,const ldb&b)
67 { return a>=b; }
68
69 ldb d[105000];
70 ldb A[105000];
71 ldb B[105000];
72 ldb R[105000];
73
74 ldb X[105000];
75 ldb Y[105000];
76 ldb K[105000];
77 bool kcmp(const int&a,const int&b)
78 { return K[a]>=K[b]; }
79
80 point s[105000]; int st;
81
82 int h[105000];
83 int q[105000];
84 int p[105000];
85 void DC(int l,int r)
86 {
87 if(l==r)
88 {
89 d[l]=max(d[l-1],d[l]);
90 Y[l]=d[l]/(R[l]*A[l]+B[l]);
91 X[l]=Y[l]*R[l];
92 return ;
93 }
94 int mid=(l+r)>>1;
95
96 int p1=l,p2=mid+1;
97 for(int i=l;i<=r;i++)
98 if(h[i]<=mid) q[p1++]=h[i]; else q[p2++]=h[i];
99 memcpy(h+l,q+l,sizeof(int)*(r-l+1));
100
101 DC(l,mid);
102
103 st=0;
104 s[st++]=point(0,0);
105 for(int i=l;i<=mid;i++)
106 {
107 point c(X[p[i]],Y[p[i]]);
108 while(st>1 && ConvexChange(c,s[st-1],s[st-2])) st--;
109 s[st++]=c;
110 }
111
112 int t=0;
113 for(int i=mid+1;i<=r;i++)
114 {
115 int x=h[i];
116 ldb k=K[x];
117 while(t<st-1 && SlopeBetter(s[t+1],s[t],k)) t++;
118 d[x]=max(d[x],A[x]*s[t].x+B[x]*s[t].y);
119 }
120
121 DC(mid+1,r);
122
123 t=0,p1=l,p2=mid+1;
124 while(p1<=mid && p2<=r)
125 if(X[p[p1]]<X[p[p2]]) q[t++]=p[p1++]; else q[t++]=p[p2++];
126 while(p1<=mid) q[t++]=p[p1++];
127 while(p2<=r) q[t++]=p[p2++];
128 memcpy(p+l,q,sizeof(int)*(r-l+1));
129 }
130
131 int n;
132
133 int main()
134 {
135 n=getint();
136 d[1]=d[0]=getdb();
137
138 for(int i=1;i<=n;i++)
139 A[i]=getdb(),
140 B[i]=getdb(),
141 R[i]=getdb();
142
143 for(int i=1;i<=n;i++)
144 K[i]=-(A[i]/B[i]);
145
146 for(int i=0;i<=n;i++)
147 h[i]=p[i]=i;
148
149 stable_sort(h+1,h+n+1,kcmp);
150
151 DC(1,n);
152
153 cout.precision(3);
154 cout<<fixed;
155 cout<<d[n]<<endl;
156
157 return 0;
158 }
用 long double 只比 double 慢了总共 88ms ...
...