hdu5306 Gorgeous Sequence

留了几天的坑终于填了。。。

这个东西是线段树取区间最值问题。。。在吉司机16的论文里面。。。

其实就是让修改值和区间次大比较,假如次大较小就可以只改最大值,维护一下就可以了

注意到标记大小是按深度递增递增的

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;

struct node
{
    LL mx,mxc,sx,sum,md;
}tr[2100000];int trlen,a[1100000];

void update(int now)
{
    int lc=now<<1,rc=now<<1|1;
    tr[now].sum=tr[lc].sum+tr[rc].sum;
    tr[now].mx=max(tr[lc].mx,tr[rc].mx);

    tr[now].mxc=0;
    if(tr[lc].mx==tr[now].mx)tr[now].mxc+=tr[lc].mxc;
    if(tr[rc].mx==tr[now].mx)tr[now].mxc+=tr[rc].mxc;

    tr[now].sx=max(tr[lc].sx,tr[rc].sx);
    if(tr[lc].mx!=tr[rc].mx)
        tr[now].sx=max(tr[now].sx,min(tr[lc].mx,tr[rc].mx));
}
void pushdown(int now)
{
    if(tr[now].md!=0)
    {
        int lc=now<<1,rc=now<<1|1;
        if(tr[lc].mx>tr[now].md)
        {
            tr[lc].sum-=tr[lc].mxc*(tr[lc].mx-tr[now].mx);
            tr[lc].mx=tr[lc].md=tr[now].md;
        }
        if(tr[rc].mx>tr[now].md)
        {
            tr[rc].sum-=tr[rc].mxc*(tr[rc].mx-tr[now].mx);
            tr[rc].mx=tr[rc].md=tr[now].md;
        }
    }
}
//~~~~~~~~~~~~~~tool~~~~~~~~~~~~~~~~~~~~~~~~~

void bt(int now,int ql,int qr)
{
    if(ql==qr)
    {
        tr[now].mx=tr[now].sum=a[ql];
        tr[now].mxc=1;
        tr[now].sx=-1;
    }
    else
    {
        int mid=(ql+qr)/2;
        int lc=now<<1,rc=now<<1|1;
        bt(lc,ql,mid),bt(rc,mid+1,qr);
        update(now);
    }
    tr[now].md=0;
}
void change(int now,int ql,int qr,int l,int r,LL k)
{
    if(tr[now].mx<=k)return ;
    if(ql==qr){tr[now].mx=tr[now].sum=k;return ;}
    int mid=(ql+qr)/2;
    int lc=now<<1,rc=now<<1|1;

    if(ql==l&&qr==r)
    {
        if(tr[now].sx<k)
        {
            tr[now].sum-=tr[now].mxc*(tr[now].mx-k);
            tr[now].mx=tr[now].md=k;
            return ;
        }
        else
        {
            change(lc,ql,mid,l,mid,k),change(rc,mid+1,qr,mid+1,r,k);
            update(now);
        }
    }
    else
    {
        pushdown(now);
             if(r<=mid)  change(lc,ql,mid,l,r,k);
        else if(mid+1<=l)change(rc,mid+1,qr,l,r,k);
        else change(lc,ql,mid,l,mid,k),change(rc,mid+1,qr,mid+1,r,k);
        update(now);
    }
}
//~~~~~~~~~~~~~~~~~~~~~~change~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

LL getmax(int now,int ql,int qr,int l,int r)
{
    if(ql==l&&qr==r)return tr[now].mx;

    int mid=(ql+qr)/2;
    int lc=now<<1,rc=now<<1|1;
    pushdown(now);

         if(r<=mid)  return getmax(lc,ql,mid,l,r);
    else if(mid+1<=l)return getmax(rc,mid+1,qr,l,r);
    else return max(getmax(lc,ql,mid,l,mid),getmax(rc,mid+1,qr,mid+1,r));
}
LL getsum(int now,int ql,int qr,int l,int r)
{
    if(ql==l&&qr==r)return tr[now].sum;

    int mid=(ql+qr)/2;
    int lc=now<<1,rc=now<<1|1;
    pushdown(now);

         if(r<=mid)  return getsum(lc,ql,mid,l,r);
    else if(mid+1<=l)return getsum(rc,mid+1,qr,l,r);
    else return getsum(lc,ql,mid,l,mid)+getsum(rc,mid+1,qr,mid+1,r);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~solve~~~~~~~~~~~~~~~~~~~~~~~~~~

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        trlen=0;bt(1,1,n);

        int op,x,y;LL d;
        while(m--)
        {
            scanf("%d",&op);
            if(op==0)
            {
                scanf("%d%d%lld",&x,&y,&d);
                change(1,1,n,x,y,d);
            }
            else
            {
                scanf("%d%d",&x,&y);
                if(op==1)printf("%lld\n",getmax(1,1,n,x,y));
                else printf("%lld\n",getsum(1,1,n,x,y));
            }
        }
    }

    return 0;
}

原文地址:https://www.cnblogs.com/AKCqhzdy/p/10242335.html

时间: 2024-10-16 03:50:15

hdu5306 Gorgeous Sequence的相关文章

[HDU5306]Gorgeous Sequence(标记回收线段树)

题意:维护一个序列,支持区间与一个数取min,询问区间最大,询问区间和(序列长度<=1e6) 分析: http://www.shuizilong.com/house/archives/hdu-5306-gorgeous-sequence/?variant=zh-cn 在建树的时候,就已经生成了lazy标记,具体的参加jry的16年集训队论文 这样使得lazy标记有了这一样一个性质:子节点向上走碰到的第一个lazy的值就是此节点的值 打标记操作: 标记回收操作:

hdu 5306 Gorgeous Sequence(区间最值更新+求和)

题目链接:hdu 5306 Gorgeous Sequence 题意: 给你一个序列,有三种操作. 0 x y t:将[x,y]的数取min(a[i],t) 1 x y:求[x,y]的最大值 2 x y:求[x,y]的区间和 题解: 吉老师的课件题:传送门 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 #define ls l,m,rt<<1 4 #define rs m+1,r,rt

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

HDOJ 5306 Gorgeous Sequence 线段树

http://www.shuizilong.com/house/archives/hdu-5306-gorgeous-sequence/ Gorgeous Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 440    Accepted Submission(s): 87 Problem Description Th

HDU 5306 Gorgeous Sequence

参考 关键是加一个标记cv:这个区间有多少个结点,已被 tag 影响. Gorgeous Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 396    Accepted Submission(s): 78 Problem Description There is a sequence a of length n.

hdu 5306 Gorgeous Sequence(线段树)

题目链接:hdu 5306 Gorgeous Sequence 和普通的线段树一样一个标记值T,然后另外加一个C值记录以u为根节点的子树下有多少个叶子节点被T值控制.每次修改时,dfs到叶子节点之后在修改该节点.维护sum值时只要额外加上T值控制下的节点.加了个输入外挂,时间少了将近1000ms. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const in

Gorgeous Sequence(线段树)

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

【HDU5306】Gorgeous Sequence

这个题目是Segment-Tree-beats的论文的第一题. 首先我们考虑下这个问题的不同之处在于,有一个区间对x取max的操作. 那么如何维护这个操作呢? 就是对于线段树的区间,维护一个最大值标记,最大值出现次数,以及严格次大值. 接下来考虑处理操作. 首先如果x>maxv[o]证明已经是无所谓的,所以应该直接放弃. 如果v处于semx[o]<x<maxv[o],证明只有最大值需要被修改. 其他的情况就继续向下递进就可以了. 那么我们证明一下为什么这么做复杂度是对的. 首先,如同论文

【hdu5306】Gorgeous Sequence 线段树区间最值操作

题目描述 给你一个序列,支持三种操作: $0\ x\ y\ t$ :将 $[x,y]$ 内大于 $t$ 的数变为 $t$ :$1\ x\ y$ :求 $[x,y]$ 内所有数的最大值:$2\ x\ y$ :求 $[x,y]$ 内所有数的和. 多组测试数据,$\sum n,\sum m\le 10^6$ 题解 线段树区间最值操作 对于线段树上的一个节点,维护对应区间的:最大值 $mx$ .最大值个数 $c$ 及严格次大值 $se$ .那么对于一次区间最小值操作: 如果 $t\ge mx$ ,则这个