BZOJ1568: [JSOI2008]Blue Mary开公司【李超树】

Description

Input

第一行 :一个整数N ,表示方案和询问的总数。

接下来N行,每行开头一个单词“Query”或“Project”。

若单词为Query,则后接一个整数T,表示Blue Mary询问第T天的最大收益。

若单词为Project,则后接两个实数S,P,表示该种设计方案第一天的收益S,以及以后每天比上一天多出的收益P。

1 <= N <= 100000 1 <= T <=50000 0 < P < 100,| S | <= 10^6

提示:本题读写数据量可能相当巨大,请选手注意选择高效的文件读写方式。

Output

对于每一个Query,输出一个整数,表示询问的答案,并精确到整百元(以百元为单位,

例如:该天最大收益为210或290时,均应该输出2)。没有方案时回答询问要输出0

Sample Input

10
Project 5.10200 0.65000
Project 2.76200 1.43000
Query 4
Query 2
Project 3.80200 1.17000
Query 2
Query 3
Query 1
Project 4.58200 0.91000
Project 5.36200 0.39000

Sample Output

0
0
0
0
0


李超树模板题

很简单的好吧,就是一开始忘了对k分类讨论

用线段树来存储每个区间的相对最优解

这里用到了一个永久化标记的思想

这个东西很好啊,每个节点记录区间的相对最优解之后

直接dfs到叶子节点把路径上经过的所有节点的权值全部取max就可以了

正确性非常显然,但是怎么维护呢?

我们假设当前要更新的是一个节点\(p_t\),那么如果\(p_t\)的k大于拿来更新的\(val\)的k

如果在\(mid\)\(p_t\)大于\(val\),那么显然在\([mid+1,r]\)这个区间里val不可能比\(p_t\)更优

所以就把\(val\)递归到左区间更新

如果在\(mid\)\(p_t\)小于\(val\),那么在\([l,mid]\)这个区间\(p_t\)不可能比\(val\)更优

所以就把\(p_t\)递归到右区间,再把\(p_t\)替换成val就可以了


//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
  bool w = 1;x = 0;
  char c = getchar();
  while (!isdigit(c) && c != '-') c = getchar();
  if (c == '-') w = 0, c = getchar();
  while (isdigit(c)) {
    x = (x<<1) + (x<<3) + c -'0';
    c = getchar();
  }
  if (!w) x = -x;
}
template <typename T>
void Write(T x) {
  if (x < 0) {
    putchar('-');
    x = -x; 
  }
  if (x > 9) Write(x / 10);
  putchar(x % 10 + '0');
}
//----------------------------------------------
#define LD (t << 1)
#define RD (t << 1 | 1)
const int MAXN = 5e4;
struct Line {
  double k, b;
} p[(MAXN << 2) + 10];
double calc(int x, Line a) {
  return a.k * (double) x + a.b;
}
bool cmp(int x, Line a, Line b) {
  return calc(x, a) > calc(x, b); 
}
void modify(int t, int l, int r, Line vl) {
  if (l == r) {
    if (cmp(l, vl, p[t])) p[t] = vl;
    return;
  }
  int mid = (l + r) >> 1;
  if (p[t].k <= vl.k) {
    if (cmp(mid, vl, p[t])) {
      modify(LD, l, mid, p[t]);
      p[t] = vl;
    } else {
      modify(RD, mid + 1, r, vl);
    }
  } else {
    if (cmp(mid, vl, p[t])) {
      modify(RD, mid + 1, r, p[t]);
      p[t] = vl;
    } else {
      modify(LD, l, mid, vl);
    }
  }
}
double query(int t, int l, int r, int pos) {
  if (l == r) return calc(pos, p[t]);
  int mid = (l + r) >> 1;
  if (pos <= mid) return max(calc(pos, p[t]), query(LD, l, mid, pos));
  else  return max(calc(pos, p[t]), query(RD, mid + 1, r, pos));
}
int n;
char c[10];
int main() {
  Read(n);
  while (n--) {
    scanf("%s", c);
    if (c[0] == 'P') {
      Line now;
      scanf("%lf%lf", &now.b, &now.k);
      now.b -= now.k;
      modify(1, 1, MAXN, now);
    } else {
      int x; Read(x);
      printf("%d\n", (int)query(1, 1, MAXN, x) / 100);
    }
  }
  return 0;
}
posted @ 2018-10-29 14:35  Dream_maker_yk  阅读(276)  评论(0编辑  收藏  举报