题目大意:给你一个序列a,你有三个操作,0: x y t将a[x,y]和t取min;1:x y求a[x,y]的最大值;2:x y求a[x,y]的sum

题解:首先很明显就是线段树裸题,那么考虑如何维护

区间最大值和区间sum很好维护,0操作不好做,那么考虑怎么快速解决0操作

很容易想到维护区间最大值和区间是否全部相同,这是一个做法,但是时间复杂度上却不正确,但也给了我们一个思路,可以通过维护最大值之类的数来加快操作

一个不行就两个,于是考虑维护次大值,那么每次0操作就有三种情况,一:比区间最大值还大,那么直接返回;二:大于区间次大值小于区间最大值,那么可以直接修改区间;三:小于区间次大值,那么继续递归下去;

这么做是可行的,在更新区间时因为要维护sum值,于是多维护一个区间max有多少个即可

证明略,时间复杂度o(nlog^2n)——来源:吉老师

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#define ll long long
using namespace std;
int T,n,m;
ll a[];
class Segtree
{
public:
ll sum[*],mx[*],smx[*],cnt[*],fl[*]; void pushup(int pos)
{
sum[pos]=sum[pos<<]+sum[pos<<|];
if(mx[pos<<]>mx[pos<<|])
{
mx[pos]=mx[pos<<];
cnt[pos]=cnt[pos<<];
if(mx[pos<<|]>smx[pos<<])smx[pos]=mx[pos<<|];
else smx[pos]=smx[pos<<];
}
if(mx[pos<<]<mx[pos<<|])
{
mx[pos]=mx[pos<<|];
cnt[pos]=cnt[pos<<|];
if(mx[pos<<]>smx[pos<<|])smx[pos]=mx[pos<<];
else smx[pos]=smx[pos<<|];
}
if(mx[pos<<]==mx[pos<<|])
{
mx[pos]=mx[pos<<];
cnt[pos]=cnt[pos<<]+cnt[pos<<|];
if(smx[pos<<]>smx[pos<<|])smx[pos]=smx[pos<<];
else smx[pos]=smx[pos<<|];
}
}
void pushdown(int pos)
{
if(fl[pos]>=)
{
if(mx[pos<<]>fl[pos])
{
sum[pos<<]-=(mx[pos<<]-fl[pos])*cnt[pos<<];
fl[pos<<]=mx[pos<<]=fl[pos];
}
if(mx[pos<<|]>fl[pos])
{
sum[pos<<|]-=(mx[pos<<|]-fl[pos])*cnt[pos<<|];
fl[pos<<|]=mx[pos<<|]=fl[pos];
}
fl[pos]=-;
}
}
void build(int l,int r,int pos)
{
if(l==r)
{
sum[pos]=mx[pos]=a[l];
cnt[pos]=;
fl[pos]=smx[pos]=-;
return;
}
int mid=l+r>>;
build(l,mid,pos<<);
build(mid+,r,pos<<|);
pushup(pos);
fl[pos]=-;
}
void change(int l,int r,int al,int ar,ll v,int pos)
{
int mid=l+r>>;
if(l==al && r==ar)
{
if(v>=mx[pos])return;
if(smx[pos]<v && v<mx[pos])
{
sum[pos]-=(mx[pos]-v)*cnt[pos];
fl[pos]=mx[pos]=v;
return;
}
change(l,mid,al,mid,v,pos<<);
change(mid+,r,mid+,ar,v,pos<<|);
pushup(pos);
return;
}
pushdown(pos);
if(ar<=mid)change(l,mid,al,ar,v,pos<<);
if(al>mid)change(mid+,r,al,ar,v,pos<<|);
if(al<=mid && ar>mid){change(l,mid,al,mid,v,pos<<);change(mid+,r,mid+,ar,v,pos<<|);}
pushup(pos);
}
ll askmax(int l,int r,int al,int ar,int pos)
{
if(l==al && r==ar)return mx[pos];
int mid=l+r>>;
pushdown(pos);
if(ar<=mid)return askmax(l,mid,al,ar,pos<<);
if(al>mid)return askmax(mid+,r,al,ar,pos<<|);
if(al<=mid && ar>mid)
{
ll t1=askmax(l,mid,al,mid,pos<<),t2=askmax(mid+,r,mid+,ar,pos<<|);
return t1>t2?t1:t2;
}
}
ll asksum(int l,int r,int al,int ar,int pos)
{
if(l==al && r==ar)return sum[pos];
int mid=l+r>>;
pushdown(pos);
if(ar<=mid)return asksum(l,mid,al,ar,pos<<);
if(al>mid)return asksum(mid+,r,al,ar,pos<<|);
if(al<=mid && ar>mid)return asksum(l,mid,al,mid,pos<<)+asksum(mid+,r,mid+,ar,pos<<|);
}
}segtree;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%lld",&a[i]);
segtree.build(,n,);
int mod,x,y;ll t;
while(m--)
{
scanf("%d",&mod);
if(mod==)
{
scanf("%d%d%lld",&x,&y,&t);
segtree.change(,n,x,y,t,);
}
if(mod==)
{
scanf("%d%d",&x,&y);
printf("%lld\n",segtree.askmax(,n,x,y,));
}
if(mod==)
{
scanf("%d%d",&x,&y);
printf("%lld\n",segtree.asksum(,n,x,y,));
}
}
}
return ;
}

心得:有时候多维护一个次大值能解决很多问题,更多时候在不知道如何证明时间复杂度的情况下往往维护次大值是正确的

【HDU5306】【DTOJ2481】Gorgeous Sequence【线段树】的更多相关文章

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

    题目描述 给你一个序列,支持三种操作: $0\ x\ y\ t$ :将 $[x,y]$ 内大于 $t$ 的数变为 $t$ :$1\ x\ y$ :求 $[x,y]$ 内所有数的最大值:$2\ x\ y ...

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

    Gorgeous Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  3. HDOJ 5306 Gorgeous Sequence 线段树

    http://www.shuizilong.com/house/archives/hdu-5306-gorgeous-sequence/ Gorgeous Sequence Time Limit: 6 ...

  4. HDU - 5306 Gorgeous Sequence 线段树 + 均摊分析

    Code: #include<algorithm> #include<cstdio> #include<cstring> #define ll long long ...

  5. 2016暑假多校联合---Rikka with Sequence (线段树)

    2016暑假多校联合---Rikka with Sequence (线段树) Problem Description As we know, Rikka is poor at math. Yuta i ...

  6. Wow! Such Sequence!(线段树4893)

    Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others ...

  7. Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间取摸

    D. The Child and Sequence Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest ...

  8. hdu4893Wow! Such Sequence! (线段树)

    Problem Description Recently, Doge got a funny birthday present from his new friend, Protein Tiger f ...

  9. HDU 6047 Maximum Sequence(线段树)

    题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=6047 题目: Maximum Sequence Time Limit: 4000/2000 MS (J ...

  10. Codeforces 438D The Child and Sequence - 线段树

    At the children's day, the child came to Picks's house, and messed his house up. Picks was angry at ...

随机推荐

  1. linux sed如何锁定某一行数据进行替换

  2. Jenkins+Git+Gitlab+Ansible实现持续集成自动化部署静态网站

    环境准备 三台主机: 一台主机部署jenkins和作为ansible的管理主机 一台主机部署gitlab和ansible的节点1 一台主机为ansible的节点2 防火墙和apache服务关闭 第一步 ...

  3. Jmeter发送SOAP请求对WebService接口测试

    Jmeter发送SOAP请求对WebService接口测试 1.测试计划中添加一个用户自定义变量 2.HTTP信息头管理器,添加Content-Tpe,  application/soap+xml;c ...

  4. Altium Designer chapter3总结

    绘制电路原理图中需要注意的如下: (1)元件库的操作:元件库的加载和卸载.查找元件. (2)元件操作: 1.放置元件(元件库中,place part,快捷键)中place part中的history可 ...

  5. Bootstrap 学习笔记11 按钮和折叠插件

     复选框: <div class="btn-group" data-toggle="buttons"> <label for="se ...

  6. MQ基础知识学习

    之前听人提起了MQ协议,我就去稍微了解了一下什么是MQ,和MQ的一些基础性的知识. 什么是MQ呢? 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过写和检索出入列队的针对应用程序的数据 ...

  7. SQL查询返回去除重复数据的结果集

    方法一: select * from  tablename  where  id   in   (select  id  from  tablename   group  by  id   havin ...

  8. WPS for linux 中不能切换到中文输入法

    转载自:http://blog.sciencenet.cn/blog-200199-1032795.html 尽管安装有中文输入法,wps有时仍然不能切换到中文输入法,此问题解决方案如下: 根账户下打 ...

  9. 前端最常用的跨域方式--jsonp

    jsonp通过动态创建script标签的方式来实现跨域通信.原理是浏览器允许html标签在不同的域名下加载资源. <script> var script = document.create ...

  10. 10、numpy——位运算

    NumPy 位运算 NumPy "bitwise_" 开头的函数是位运算函数. NumPy 位运算包括以下几个函数: 函数 描述 bitwise_and 对数组元素执行位与操作 b ...