【BZOJ-1568】Blue Mary开公司 李超线段树 (标记可持久化)

1568: [JSOI2008]Blue Mary开公司

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 557  Solved: 192
[Submit][Status][Discuss]

Description

Input

第一行 :一个整数N ,表示方案和询问的总数。 接下来N行,每行开头一个单词“Query”或“Project”。 若单词为Query,则后接一个整数T,表示Blue Mary询问第T天的最大收益。 若单词为Project,则后接两个实数S,P,表示该种设计方案第一天的收益S,以及以后每天比上一天多出的收益P。

Output

对于每一个Query,输出一个整数,表示询问的答案,并精确到整百元(以百元为单位,例如:该天最大收益为210或290时,均应该输出2)。

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

HINT

约定: 1 <= N <= 100000 1 <= T <=50000 0 < P < 100,| S | <= 10^6 提示:本题读写数据量可能相当巨大,请选手注意选择高效的文件读写方式。

Source

Solution

李超线段树,对于插入,相当于是在根插入,标记永久化,即标记不下推,每个点标记唯一

当插入一个新的直线,判断当前区间,即交点横坐标,以此判断优势区间,自己的理解:

至于查询,因为向下查找,所以不会有影响,复杂度$O(logn)$

可能个人理解有不对,欢迎指导

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
    while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}
    return x*f;
}
int N,M;
struct LineNode
{
    double k,b; int id;
    LineNode(int x0=0,int y0=0,int x1=0,int y1=0,int ID=0)
        {
            id=ID;
            if (x0==x1) k=0,b=max(y0,y1);
            else k=(double)(y0-y1)/(x0-x1),b=(double)y0-k*x0;
        }
    double getf(int x) {return k*x+b;}
};
bool cmp(LineNode A,LineNode B,int x)
{
    if (!A.id) return 1;
    return A.getf(x)!=B.getf(x)?A.getf(x)<B.getf(x):A.id<B.id;  //比较值直线A,B在x的值,如果A<B返回1
}
#define maxn 50010
LineNode tree[maxn<<2];
LineNode Query(int now,int l,int r,int x)
{
    if (l==r) return tree[now];
    int mid=(l+r)>>1; LineNode tmp;
    if (x<=mid) tmp=Query(now<<1,l,mid,x);
    else tmp=Query(now<<1|1,mid+1,r,x);
    return cmp(tree[now],tmp,x)?tmp:tree[now];
}
void insert(int now,int l,int r,LineNode x)
{
    if (!tree[now].id) tree[now]=x;
    if (cmp(tree[now],x,l)) swap(tree[now],x);
    if (l==r || tree[now].k==x.k) return;
    int mid=(l+r)>>1; double X=(tree[now].b-x.b)/(x.k-tree[now].k);//求交点,X为交点横坐标,判断下放区间
    if (X<l || X>r) return;
    if (X<=mid) insert(now<<1,l,mid,tree[now]),tree[now]=x;
    else insert(now<<1|1,mid+1,r,x);
}
void Insert(int now,int l,int r,int L,int R,LineNode x)
{
    if (L<=l && R>=r) {insert(now,l,r,x); return;}
    int mid=(l+r)>>1;
    if (L<=mid) Insert(now<<1,l,mid,L,R,x);
    if (R>mid) Insert(now<<1|1,mid+1,r,L,R,x);
}
int main()
{
    M=read(); N=50000;
    char opt[15];
    while (M--)
        {
            scanf("%s",opt);
            if (opt[0]==‘P‘)
                {
                    double K,B; scanf("%lf%lf",&K,&B);
                    LineNode tmp; tmp.k=B; tmp.b=K-B; tmp.id=1;
                    Insert(1,1,N,1,N,tmp);
                }
            int x;
            if (opt[0]==‘Q‘) x=read(),printf("%lld\n",(long long)(Query(1,1,N,x).getf(x)/100+1e-8));
        }
    return 0;
}

参照着zky学长的模板打的...中间有好多问题,慢慢就特别相似了(捂脸)

时间: 2024-10-08 12:15:15

【BZOJ-1568】Blue Mary开公司 李超线段树 (标记可持久化)的相关文章

P4254 [JSOI2008]Blue Mary开公司 (李超树)

题意:插入一些一次函数线段 每次询问在x = x0处这些线段的最大值 题解:李超树模版题 维护优势线段 注意这题的输入是x=1时的b #include <iostream> #include <stdio.h> using namespace std; const int MAXT = 50000; #define pff pair<double, double> int tot, rt; char s[50]; pff t[MAXT << 5]; int

BZOJ 1568: [JSOI2008]Blue Mary开公司(超哥线段树)

1568: [JSOI2008]Blue Mary开公司 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1080  Solved: 379[Submit][Status][Discuss] Description Input 第一行 :一个整数N ,表示方案和询问的总数. 接下来N行,每行开头一个单词“Query”或“Project”. 若单词为Query,则后接一个整数T,表示Blue Mary询问第T天的最大收益. 若单词为Project,则

数据结构(线段树):BZOJ 1568 [JSOI2008]Blue Mary开公司

1568: [JSOI2008]Blue Mary开公司 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 602  Solved: 214[Submit][Status][Discuss] Description Input 第 一行 :一个整数N ,表示方案和询问的总数. 接下来N行,每行开头一个单词“Query”或“Project”. 若单词为Query,则后接一个整数T,表示Blue Mary询问第T天的最大收益. 若单词为Project,则

1568: [JSOI2008]Blue Mary开公司

1568: [JSOI2008]Blue Mary开公司 题目描述 传送门 题目分析 简单分析可以发现就是不停给出了\(n\)条直线,要求每次给出一条直线后求出所有直线在横坐标为\(x\)时\(y\)的最大值. 李超树裸题. 不知道李超树的可以移步百度. 是代码呢 #include <bits/stdc++.h> using namespace std; #define ls rt<<1 #define rs rt<<1|1 #define mid ((l+r)/2)

bzoj千题计划219:bzoj1568: [JSOI2008]Blue Mary开公司

http://www.lydsy.com/JudgeOnline/problem.php?id=1568 写多了就觉着水了... #include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 100001 double a[N<<2],b[N<<2]; bool have[N<<2]; long long ans; void

Blue Mary开公司题解

Blue Mary开公司题解 李超树模板题啦,所有线段覆盖全区间,而且还是单点查询,太良心了. 什么?你不会李超树,看看我的这篇博客吧 本来不想写注释的,但为了自己以后能看懂,还是打一打吧. \(line[x]:\)存的是第\(x\)条线段的斜率和截距,\(tag[x]:\)存的是线段树上点\(x\)的优势线段是哪一条. #include<bits/stdc++.h> #define re register #define lc x<<1 #define rc x<<1

【BZOJ 1568】【JSOI 2008】Blue Mary开公司

经典的splay维护凸壳,但是看了看zky学长的题解最后决定写线段树维护标记永久化. Round1考到了这个之后一直没有理解标记永久化,CTSC也因为自己的缺陷丢掉了一些部分分,so sad 看来以后不懂的东西要及时学啊QwQ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct node { double k, b; bool p; node(int xa

bzoj1568: [JSOI2008]Blue Mary开公司 三分+二分+线段树

答案序列一定是个下凸壳,因此添加的等差数列与其之差是个单峰函数,可以先三分求出最值,再二分求出零点,然后用线段树,将得到的区间修改为一个等差数列. 这个做法应该比较好想吧,虽然比较慢…… #include<cstdio> #define Z int l=1,int r=N,int k=1 #define N 50000 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define K l,r,k

[Luogu] P4254 [JSOI2008]Blue Mary开公司

题目背景 Blue Mary 最近在筹备开一家自己的网络公司.由于他缺乏经济头脑,所以先后聘请了若干个金融顾问为他设计经营方案. 题目描述 万事开头难,经营公司更是如此.开始的收益往往是很低的,不过随着时间的增长会慢慢变好.也就是说,对于一个金融顾问 iii,他设计的经营方案中,每天的收益都比前一天高,并且均增长一个相同的量 PiP_iPi?. 由于金融顾问的工作效率不高,所以在特定的时间,Blue Mary 只能根据他已经得到的经营方案来估算某一时间的最大收益.由于 Blue Mary 是很没