hdu 5306 Gorgeous Sequence(暴力线段树)(好题)

题意:区间最大长度为1000000,

三种操作:

区间求和;

区间求最大值;

将节点值更新为当前值与给定值中的最小值(有趣的更新);

思路: 暴力线段树。关键在于处理标记,需要维护最大标记,标记覆盖范围,所在区间;

覆盖区域标记起到很关键的作用;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
  long long sum;
  int tag,maxtag,mmax,cover,s;
}q[5000100];
int num[5000100];
node  pushdown(node c,int t)  //处理标记及标记覆盖范围
{
    if(!t) return c;
    if(c.cover!=c.s) c.mmax=t;
    c.maxtag=t;
    c.sum+=1LL*(c.s-c.cover)*t;
    c.cover=c.s;
    return c;
}
node pushup(node a,node b,int t) //向上更新
{
    node c;
    c.tag=t;
    c.s=a.s+b.s;
    c.sum=a.sum+b.sum;
    c.cover=a.cover+b.cover;
    c.mmax=max(a.mmax,b.mmax);
    c.maxtag=max(a.maxtag,b.maxtag);
    return pushdown(c,t);
}
void build(int l,int r,int pos)
{
    q[pos].tag=0;
    q[pos].s=r-l+1; //区间长度
    if(l<r){
        int mid=(l+r)/2;
        build(l,mid,pos*2);
        build(mid+1,r,pos*2+1);
        q[pos]=pushup(q[pos*2],q[pos*2+1],0);
    }
    else{
        q[pos].mmax=q[pos].sum=q[pos].maxtag=q[pos].tag=num[l];
        q[pos].cover=1;
    }
}
void cl(int k,int t)
{
    if(q[k].maxtag<t) return;//若已经是最小,则返回
    if(q[k].tag>=t){
        q[k].tag=0;
    }
    if(q[k].s>1){  //区间长度大于1
        cl(k*2,t);
        cl(k*2+1,t);
    }
    if(q[k].s==1){ //处理点
        q[k].sum=q[k].mmax=q[k].maxtag=q[k].tag;
        q[k].cover=(q[k].tag>0); //决定是否覆盖
    }
    else{ //更新
        q[k]=pushup(q[k*2],q[k*2+1],q[k].tag);
    }
}
void update(int L,int R,int t,int l,int r,int pos)
{
    if(q[pos].tag&&q[pos].tag<=t) return; //已是最小,则不用update
    if(L<=l&&r<=R){
        cl(pos,t);  //区间处理
        q[pos].tag=t;
        if(l==r){
            q[pos].mmax=q[pos].maxtag=q[pos].sum=q[pos].tag=t;
            q[pos].cover=(q[pos].tag>0); //是否覆盖
        }
        else{
            q[pos]=pushup(q[pos*2],q[pos*2+1],t);
        }
    }
    else{
        int mid=(l+r)/2;
        if(R<=mid) update(L,R,t,l,mid,pos*2);
        else if(mid<L) update(L,R,t,mid+1,r,pos*2+1);
        else update(L,R,t,l,mid,pos*2),update(L,R,t,mid+1,r,pos*2+1);
        q[pos]=pushup(q[pos*2],q[pos*2+1],q[pos].tag);
    }
}
node query(int L,int R,int l,int r,int pos)
{
    if(L<=l&&r<=R){
      return q[pos];
    }
    int mid=(l+r)/2;
    if(R<=mid) return pushdown(query(L,R,l,mid,pos*2),q[pos].tag); //查询时,区间处理
    if(mid<L) return pushdown(query(L,R,mid+1,r,pos*2+1),q[pos].tag);
    return pushup(query(L,R,l,mid,pos*2),query(L,R,mid+1,r,pos*2+1),q[pos].tag);
}
int main()
{
    int t,n,m,i,j,k,temp;
    int a,b,c;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
            scanf("%d",&num[i]);
        build(1,n,1);
        for(i=0;i<m;i++)
        {
            scanf("%d",&temp);
            if(temp==0){
              scanf("%d%d%d",&a,&b,&c);
              update(a,b,c,1,n,1);
            }
            else if(temp==1){
              scanf("%d%d",&a,&b);
              printf("%d\n",query(a,b,1,n,1).mmax);
            }
            else{
              scanf("%d%d",&a,&b);
              printf("%lld\n",query(a,b,1,n,1).sum);
            }
        }
    }
    return 0;
}
时间: 2024-10-05 09:56:19

hdu 5306 Gorgeous Sequence(暴力线段树)(好题)的相关文章

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

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

【模板】吉司机线段树 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))

HDU 6047 Maximum Sequence(贪心+线段树)

题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=6047 题目: Maximum Sequence Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 90    Accepted Submission(s): 44 Problem Description Steph is extremely o

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.

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

hdu - 1394 Minimum Inversion Number(线段树水题)

http://acm.hdu.edu.cn/showproblem.php?pid=1394 很基础的线段树. 先查询在更新,如果后面的数比前面的数小肯定会查询到前面已经更新过的值,这时候返回的sum就是当前数的逆序数. 这样查询完之后得到初始数列的逆序数,要求得所有序列的最小逆序数,还需要循环一次. 设初始序列abcde中逆序数为k,小于a的个数是t-1那么大于a的个数就是n-t,当把a左移一位,原来比a大的都变成了a的逆序对,即逆序数增加了n-t,但是原来比a小的数都变成了顺序, 因此逆序数

HDU 4521-小明序列(线段树好题)

题意: n个数字的序列,求各数位置间隔大于d的最长上升子序列 分析: 最基本的dp但是数据量大O(n^2)肯定超时 前dp[i]为的最长上升子序列是由前dp[1]---dp[i-d-1]符合条件的最大值得到,我们可以用线段树维护dp[1]---dp[i-d-1]的最大值 #include <map> #include <set> #include <list> #include <cmath> #include <queue> #include