暑假集训8.7数据结构专题-线段树存直线

题目: E-card oj1811

思路:线段树内存直线的k和b,线段树存x,当某个区间的左右端点代入关系始终严格优于或劣于带修改的值,则修改区间。否则继续分散到两个子区间重复操作。

代码:

#include<bits/stdc++.h>
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=100005;
struct node{int l,r,a,b;}q[N];struct Tree{LL k,b;}t[N*12];
int n,m,b[N*3],cnt;LL maxn[N*12];
int read(){int x,f=1;char ch;_(!)ch==‘-‘?f=-1:f;x=ch-48;_()x=x*10+ch-48;return f*x;}
void update(int x,int l,int r,int ql,int qr,LL k,LL bi){
    int mid=(l+r)>>1;
    if(ql<=l&&r<=qr){
        LL q1,q2,w1,w2;w1=(LL)b[l]*k+bi;w2=(LL)b[r]*k+bi;
      q1=(LL)b[l]*t[x].k+t[x].b;q2=(LL)b[r]*t[x].k+t[x].b;
        if(w1<=q1&&w2<=q2)return;
      if(w1>q1&&w2>q2){t[x].k=k;t[x].b=bi;return;}if(l==r)return;
      update(x<<1,l,mid,ql,qr,k,bi);update(x<<1|1,mid+1,r,ql,qr,k,bi);return;
    }
    if(ql<=mid)update(x<<1,l,mid,ql,qr,k,bi);
    if(mid<qr)update(x<<1|1,mid+1,r,ql,qr,k,bi);
}
LL query(int x,int l,int r,int pos){
    LL res;res=(LL)b[pos]*t[x].k+t[x].b;
    if(l==r)return res;int mid=(l+r)>>1;
    if(pos<=mid)res=max(res,query(x<<1,l,mid,pos));
    else res=max(res,query(x<<1|1,mid+1,r,pos));
    return res;
}
void change(int x,int l,int r,int pos,LL res){
    if(l==r){maxn[x]=max(res,maxn[x]);return;}int mid=(l+r)>>1;
    if(pos<=mid)change(x<<1,l,mid,pos,res);
    else change(x<<1|1,mid+1,r,pos,res);
    maxn[x]=max(maxn[x<<1],maxn[x<<1|1]);
}
int getans(int x,int l,int r){
    if(l==r)return l;int mid=(l+r)>>1;
    if(maxn[x<<1]>=maxn[x<<1|1])return getans(x<<1,l,mid);
    else return getans(x<<1|1,mid+1,r);
}
int main()
{
    n=read();m=read();b[++cnt]=1;
    for(int i=1;i<=m;i++){
        int op;op=read();
        if(op==1){q[i].l=read();q[i].r=read();q[i].a=read();q[i].b=read();b[++cnt]=q[i].l;b[++cnt]=q[i].r;}
        else {q[i].l=read();q[i].r=0;b[++cnt]=q[i].l;}
    }
    sort(b+1,b+1+cnt);cnt=unique(b+1,b+1+cnt)-b-1;
    for(int i=1;i<=m;i++){
        if(q[i].r==0){
            q[i].l=lower_bound(b+1,b+1+cnt,q[i].l)-b;
            LL res;res=query(1,1,cnt,q[i].l);change(1,1,cnt,q[i].l,res);printf("%d\n",b[getans(1,1,cnt)]);
        }
        else{
            q[i].l=lower_bound(b+1,b+1+cnt,q[i].l)-b;q[i].r=lower_bound(b+1,b+1+cnt,q[i].r)-b;
            update(1,1,cnt,q[i].l,q[i].r,(LL)q[i].a,(LL)q[i].b-(LL)q[i].a*(LL)b[q[i].l]);
        }
    }
  return 0;
}

这个思路也可以运用到带条件的斜率优化,用线段树维护斜率优化(oj3629)

原文地址:https://www.cnblogs.com/Jessie-/p/9440412.html

时间: 2024-07-30 07:38:22

暑假集训8.7数据结构专题-线段树存直线的相关文章

暑假集训8.7数据结构专题-很妙的线段树( 觉醒力量(hidpower))

题目:oj1710 因为存在修改和查询的操作,所以学长说可以很"轻易"的想到线段树....,装作我轻易的想到了,最后是要输出答案mod17及mod46189的结果,(关键点1)然后我们发现46189=11*13*17*19:于是我们想到但处理出答案mod每个质因数的答案,再利用中国剩余定理求出答案.(关键点2)考虑对枚举进入某各区间运算的数为1-p[i],因为p[i]很小所以可以处理.然后修改操作也变成log的.非常可写. 关于中国剩余定理:x=(∑ai*ti*mi)modM.ti是逆

《数据结构》线段树入门(二)

今天继续介绍——线段树之延迟标记 接上期<数据结构>线段树入门(一):http://www.cnblogs.com/shadowland/p/5870339.html 在上期介绍了线段树的最基本内容(线段树单点修改,区间查询),这次将介绍:区间修改,区间查询. Question: 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和. 输入描述: 第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,每行表示操作的个数,如果第一数是1,后接3个正

《ACM/ICPC 算法训练教程》读书笔记 之 数据结构(线段树详解)

依然延续第一篇读书笔记,这一篇是基于<ACM/ICPC 算法训练教程>上关于线段树的讲解的总结和修改(这本书在线段树这里Error非常多),但是总体来说这本书关于具体算法的讲解和案例都是不错的. 线段树简介 这是一种二叉搜索树,类似于区间树,是一种描述线段的树形数据结构,也是ACMer必学的一种数据结构,主要用于查询对一段数据的处理和存储查询,对时间度的优化也是较为明显的,优化后的时间复杂为O(logN).此外,线段树还可以拓展为点树,ZWK线段树等等,与此类似的还有树状数组等等. 例如:要将

《数据结构》线段树入门(一)

今天介绍一种非常特殊的数据结构——线段树 首先提出一个问题: 给你n个数,有两种操作: 1:给第i个数的值增加X 2:询问区间[a,b]的总和是什么? 输入描述 输入文件第一行为一个整数n,接下来是n行n个整数,表示格子中原来的整数.接下一个正整数q,再接 下来有q行,表示q个询问,第一个整数表示询问代号,询问代号1表示增加,后面的两个数x和A表示给 位置X上的数值增加A,询问代号2表示区间求和,后面两个整数表示a和b,表示要求[a,b]之间的区间和. 样例输入 4 7 6 3 5 2 1 1

【loj6029】「雅礼集训 2017 Day1」市场 线段树+均摊分析

题目描述 给出一个长度为 $n$ 的序列,支持 $m$ 次操作,操作有四种:区间加.区间下取整除.区间求最小值.区间求和. $n\le 100000$ ,每次加的数在 $[-10^4,10^4]$ 之间,每次除的数在 $[2,10^9]$ 之间. 题解 线段树+均摊分析 和 [uoj#228]基础数据结构练习题 类似的均摊分析题. 对于原来的两个数 $a$ 和 $b$ ( $a>b$ ) ,原来的差是 $a-b$ ,都除以 $d$ 后的差是 $\frac{a-b}d$ ,相当于差也除了 $d$

【数据结构】线段树 (定义 &amp; 点修改/区间查询)

[本文描述高级数据结构线段树的定义] [并解决 点修改/区间查询 的问题] 结构与定义 线段树的基本结构 ? 由图可知,线段树的每一个节点都代表着一段区间 且同一层的节点(深度相同的节点)所表示的区间互不重叠 所有叶子节点代表的区间左边界与右边界相同(叶子节点代表单个元素) 普遍规定 如果某个非叶子节点代表的区间包含元素个数为奇数 则它的左儿子包含的元素个数比右儿子大 1 在代码部分,非叶子节点表示区间为 [l,r] 则左儿子为 [ l , (l+r)/2 ] ,右儿子为 [ (l+r)/2+1

kb-07专题线段树-04--离散化;

1 /* 2 poj2528 3 线段树 好题,用到了离散化,二分定位,特殊的区间查寻方式:在下面的代码注释中有详细的解释: 4 */ 5 #include<iostream> 6 #include<cstdio> 7 #include<cstring> 8 #include<algorithm> 9 10 using namespace std; 11 typedef struct 12 { 13 int l,r; 14 int cnt;//记录该段有几张

kb-07专题--线段树-01-单点修改,区间查和

给定区间长度,然后给两个操作,单点增加值和单点减值,询问一个区间的人数和:(水) 代码如下: 1 /* 2 写的第一个线段树,丑: 3 */ 4 #include<iostream> 5 #include<cstdio> 6 #include<cstring> 7 #include<algorithm> 8 using namespace std; 9 typedef struct 10 { 11 int l,r; 12 int value; 13 }tr[

数据结构2——线段树

一.相关介绍 线段树:它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题.由于二叉结构的特性,它基本能保持每个操作的复杂度为O(logn). 线段树的每个节点表示一个区间,子节点则分别表示父节点的左右半区间,例如父亲的区间是[a,b],那么(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b]. 下面我们从一个经典的例子来了解线段树,问题描述如下: 从数组arr[0...n-1]中查找某个(子)数组内的最小值,其中数组大小固定,但是数组中