题意:
n幢摩天大楼,第i幢初始高度为a[i],每个单位时间增长b[i]。
询问区间[x,y]的大楼在t时刻的最大高度。
虽然是区间查询,线段树不会搞。
先读入询问,对时间非降排序,离线搞是很显然的。
分成sqrt(n)块,在区间内的每块在常数时间内得到答案,两端暴力答案。
高度y[i]=a[i]+b[i]*t,是直线方程。所以每块在常数时间得到答案,就要维护每块直线的单调性,剔除不影响答案的直线。
由于块内答案是递增的,所以直线的斜率也是递增的。所以对每块的直线斜率非降排序。
设有k1,k2,k3三条直线,且斜率递增,若k1与k2的交点在k3的下方,那么k2显然是多余的。
纸上yy一下,比较时把除法化为乘法,类似求凸包的思想就可以做到的。
总复杂度 O(nsqrt(n))。
1 #include2 #include 3 #include 4 #include 5 #include 6 typedef long long LL; 7 #define MAXN 100010 8 #define MAXM 320 9 #define EPS 1e-8 10 using namespace std; 11 int n, block; 12 struct node { 13 int pos, high, inc; 14 }; 15 struct seg { 16 int pos, x, y, t; 17 }; 18 node a[MAXN]; 19 seg p[MAXN]; 20 vector b[MAXM]; 21 int pt[MAXM], ans[MAXN]; 22 inline bool cmp1(seg a, seg b) { 23 return a.t < b.t; 24 } 25 inline bool cmp2(node a, node b) { 26 return a.inc < b.inc; 27 } 28 void Init() { 29 int i; 30 memset(pt, 0, sizeof(pt)); 31 block = (int) (ceil(sqrt((double) n)) + EPS); 32 for (i = 0; i < block; i++) 33 b[i].clear(); 34 } 35 inline bool Delete(LL a0, LL b0, LL a1, LL b1, LL a2, LL b2) { 36 return b0 * a1 - a0 * b1 <= a2 * (b0 - b1) + b2 * (a1 - a0); 37 } 38 void Increase() { 39 int i, j, k; 40 vector tmp; 41 for (i = 0; i < block; i++) { 42 tmp.clear(); 43 for (j = 0; j < (int) b[i].size(); j++) 44 tmp.push_back(b[i][j]); 45 b[i].clear(); 46 sort(tmp.begin(), tmp.end(), cmp2); 47 for (j = 0; j < (int) tmp.size(); j++) { 48 while (b[i].size() > 1) { 49 k = (int) b[i].size() - 1; 50 if (Delete(b[i][k].high, b[i][k].inc, b[i][k - 1].high, 51 b[i][k - 1].inc, tmp[j].high, tmp[j].inc)) 52 b[i].pop_back(); 53 else 54 break; 55 } 56 b[i].push_back(tmp[j]); 57 } 58 } 59 } 60 int Query(int x, int y, int t) { 61 LL res, tmp; 62 int pos, nd, p, q, i; 63 p = x / block; 64 q = y / block; 65 res = 0; 66 if (p == q) { 67 for (i = x; i <= y; i++) { 68 tmp = (LL) a[i].inc * t + a[i].high; 69 if (tmp > res) { 70 res = tmp; 71 pos = i; 72 } 73 } 74 } else { 75 if (x % block) { 76 for (nd = min(p * block + block, n); x < nd; x++) { 77 tmp = (LL) a[x].inc * t + a[x].high; 78 if (tmp > res) { 79 res = tmp; 80 pos = x; 81 } 82 } 83 } 84 if (y % block != block - 1) { 85 for (nd = max(q * block, 1); y >= nd; y--) { 86 tmp = (LL) a[y].inc * t + a[y].high; 87 if (tmp > res) { 88 res = tmp; 89 pos = y; 90 } 91 } 92 } 93 for (p = x / block; x <= y; x += block, p++) { 94 while (pt[p] < (int) b[p].size() - 1) { 95 if ((LL) b[p][pt[p]].inc * t + b[p][pt[p]].high 96 <= (LL) b[p][pt[p] + 1].inc * t + b[p][pt[p] + 1].high) 97 pt[p]++; 98 else 99 break;100 }101 tmp = (LL) b[p][pt[p]].inc * t + b[p][pt[p]].high;102 if (tmp > res) {103 res = tmp;104 pos = b[p][pt[p]].pos;105 }106 }107 }108 return pos;109 }110 int main() {111 int i, q;112 while (~scanf("%d%d", &n, &q)) {113 Init();114 for (i = 1; i <= n; i++) {115 scanf("%d%d", &a[i].high, &a[i].inc);116 a[i].pos = i;117 b[i / block].push_back(a[i]);118 }119 for (i = 0; i < q; i++) {120 scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].t);121 p[i].pos = i;122 }123 sort(p, p + q, cmp1);124 Increase();125 for (i = 0; i < q; i++)126 ans[p[i].pos] = Query(p[i].x, p[i].y, p[i].t);127 for (i = 0; i < q; i++)128 printf("%d\n", ans[i]);129 }130 return 0;131 }