HDU 5306 吉司机线段树

思路:

后面nlogn的部分是伪证...

大家可以构造数据证明是这是nlog^2n的啊~

吉老司机翻车了

//By SiriusRen
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1000050;
int cases,n,m,op,xx,yy,zz;
typedef long long ll;
struct SegTree{int max1,max2,maxnum,lazy;ll sum;}tr[N*8];
void push_up(int pos){
    tr[pos].max2=0;int lson=pos<<1,rson=pos<<1|1;
    tr[pos].max1=max(tr[lson].max1,tr[rson].max1);
    if(tr[lson].max1==tr[rson].max1)
        tr[pos].maxnum=tr[lson].maxnum+tr[rson].maxnum,
        tr[pos].max1=tr[lson].max1,
        tr[pos].max2=max(tr[lson].max2,tr[rson].max2);
    else{
        tr[lson].max1>tr[rson].max1?tr[pos]=tr[lson]:tr[pos]=tr[rson];
        tr[pos].max2=max(tr[lson].max2,tr[rson].max2);
        if(tr[pos].max1==tr[lson].max1)tr[pos].max2=max(tr[pos].max2,tr[rson].max1);
        else tr[pos].max2=max(tr[pos].max2,tr[lson].max1);
    }tr[pos].sum=tr[lson].sum+tr[rson].sum;
}
void change(int pos,int wei){
    tr[pos].sum-=(1ll*tr[pos].max1-wei)*tr[pos].maxnum;
    tr[pos].max1=tr[pos].lazy=wei;
}
void push_down(int pos){
    int lson=pos<<1,rson=pos<<1|1;
    if(tr[lson].max1>tr[pos].lazy)change(lson,tr[pos].lazy),tr[lson].lazy=tr[pos].lazy;
    if(tr[rson].max1>tr[pos].lazy)change(rson,tr[pos].lazy),tr[rson].lazy=tr[pos].lazy;
    tr[pos].lazy=-1;
}
void build(int l,int r,int pos){
    tr[pos].lazy=-1,tr[pos].max2=0;
    if(l==r){scanf("%d",&tr[pos].max1),tr[pos].sum=tr[pos].max1,tr[pos].maxnum=1;return;}
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    build(l,mid,lson),build(mid+1,r,rson),push_up(pos);
}
void insert(int l,int r,int pos,int L,int R,int wei){
    if(~tr[pos].lazy)push_down(pos);
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(l>=L&&r<=R){
        if(wei>=tr[pos].max1)return;
        else if(wei<tr[pos].max1&&wei>tr[pos].max2){change(pos,wei);return;}
        else insert(l,mid,lson,L,R,wei),insert(mid+1,r,rson,L,R,wei);
    }
    if(mid<L)insert(mid+1,r,rson,L,R,wei);
    else if(mid>=R)insert(l,mid,lson,L,R,wei);
    else insert(l,mid,lson,L,R,wei),insert(mid+1,r,rson,L,R,wei);
    push_up(pos);
}
ll query_sum(int l,int r,int pos,int L,int R){
    if(~tr[pos].lazy)push_down(pos);
    if(l>=L&&r<=R)return tr[pos].sum;
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<L)return query_sum(mid+1,r,rson,L,R);
    else if(mid>=R)return query_sum(l,mid,lson,L,R);
    else return query_sum(l,mid,lson,L,R)+query_sum(mid+1,r,rson,L,R);
}
int query_max(int l,int r,int pos,int L,int R){
    if(~tr[pos].lazy)push_down(pos);
    if(l>=L&&r<=R)return tr[pos].max1;
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<L)return query_max(mid+1,r,rson,L,R);
    else if(mid>=R)return query_max(l,mid,lson,L,R);
    else return max(query_max(l,mid,lson,L,R),query_max(mid+1,r,rson,L,R));
}
int read(){
    char p=getchar();int x=0;
    while(p<‘0‘||p>‘9‘)p=getchar();
    while(p>=‘0‘&&p<=‘9‘)x=x*10+p-‘0‘,p=getchar();
    return x;
}
signed main(){
    scanf("%d",&cases);
    while(cases--){
        n=read(),m=read(),build(1,n,1);
        for(int i=1;i<=m;i++){
            op=read(),xx=read(),yy=read();
            if(!op)zz=read(),insert(1,n,1,xx,yy,zz);
            else if(op==1)printf("%d\n",query_max(1,n,1,xx,yy));
            else printf("%lld\n",query_sum(1,n,1,xx,yy));
        }
    }
}
时间: 2024-11-10 21:35:58

HDU 5306 吉司机线段树的相关文章

bzoj4355 Play with sequence(吉司机线段树)题解

题意: 已知\(n\)个数字,进行以下操作: \(1.\)区间\([L,R]\) 赋值为\(x\) \(2.\)区间\([L,R]\) 赋值为\(max(a[i] + x, 0)\) \(3.\)区间\([L,R]\) 询问\(0\)个数 已知初始值\(\geq 0\),\(x\geq0\). 思路: 吉司机线段树. 操作\(1\)可以直接打覆盖标记. 操作\(2\)可以分为两步:区间加\(x\),然后取区间\(max(a[i],0)\). 操作\(3\)只要维护最小值的个数,因为不管怎么操作最

【模板】吉司机线段树 HDU 5306 Gorgeous Sequence

也叫小清新线段树,用于解决区间最值修改问题 具体可以参考jiry_2神犇的集训队论文和WC2016上的PPT 此题就作为模板好了,模板的话写法是比较精妙的 #include<bits/stdc++.h> using namespace std; #define go(i,a,b) for(int i=a;i<=b;++i) #define com(i,a,b) for(int i=a;i>=b;--i) #define mem(a,b) memset(a,b,sizeof(a))

hdu6521 吉司机线段树

http://acm.hdu.edu.cn/showproblem.php?pid=6521 待填 代码 #include<bits/stdc++.h> #define ls o<<1 #define rs o<<1|1 #define ll long long using namespace std; const int MAXN = 5e5+5; int Mx[MAXN<<2],Mx2[MAXN<<2],Mn[MAXN<<2],l

HDU 5306 Gorgeous Sequence[线段树区间最值操作]

Gorgeous Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 2150    Accepted Submission(s): 594 Problem Description There is a sequence a of length n. We use ai to denote the i-th elemen

吉司机线段树思路整理[bzoj4355 Play with sequence]

原题目链接 原代码来自attack #include<cstdio> #include<algorithm> #define LL long long //#define int long long using namespace std; const int MAXN = 3 * 1e5 + 10; const LL INF = 1e10 +10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c

HDU4695 最假女选手(吉司机线段树)

本题原理和代码讲解会在近日放到b站,对题目解法不是很了解的同学可以关注b站 朝暮不思 #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<vector> #include<string> #include<cstring> #include<map> #include<set> using

HDU 4902 Nice boat(线段树)

HDU Nice boat 题目链接 题意:给定一个序列,两种操作,把一段变成x,把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 思路:线段树,每个结点多一个cover表示该位置以下区间是否数字全相同,然后每次延迟操作,最后输出的时候单点查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1

hdu 2795 Billboard(线段树)

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 10890    Accepted Submission(s): 4827 Problem Description At the entrance to the university, there is a huge rectangular billboard of

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #