Gorgeous Sequence

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 349    Accepted Submission(s): 57

Problem Description
There is a sequence a of length n. We use ai to denote the i-th element in this sequence. You should do the following three types of operations to this sequence.

0 x y t: For every x≤i≤y, we use min(ai,t) to replace the original ai's value.
1 x y: Print the maximum value of ai that x≤i≤y.
2 x y: Print the sum of ai that x≤i≤y.

 
Input
The first line of the input is a single integer T, indicating the number of testcases.
The first line contains two integers n and m denoting the length of the sequence and the number of operations.
The second line contains n separated integers a1,…,an (∀1≤i≤n,0≤ai<231).

Each of the following m lines represents one operation (1≤x≤y≤n,0≤t<231).

It is guaranteed that T=100, ∑n≤1000000, ∑m≤1000000.

 
Output
For every operation of type 1 or 2, print one line containing the answer to the corresponding query.
 
Sample Input
1
5 5
1 2 3 4 5
1 1 5
2 1 5
0 3 5 3
1 1 5
2 1 5
 
Sample Output
5
15
3
12

Hint

Please use efficient IO method

 
Source
 
解题:线段树,对着标程写的,还是没搞清到底是怎么回事
 
 #include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = ;
struct node {
int cover,s,tag,maxtag,maxv;
LL sum;
} tree[maxn<<];
node put(node c,int t) {
if(!t) return c;
if(c.cover != c.s) c.maxv = t;
c.maxtag = t;
c.sum += (LL)t*(c.s - c.cover);
c.cover = c.s;
return c;
}
node calc(const node &a,const 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.maxv = max(a.maxv,b.maxv);
c.maxtag = max(a.maxtag,b.maxtag);
return put(c,t);
}
int tmp,n,m;
void build(int L,int R,int v) {
tree[v].tag = ;
tree[v].s = R - L + ;
if(L == R) {
scanf("%d",&tmp);
tree[v].sum = tree[v].tag = tree[v].maxtag = tree[v].maxv = tmp;
tree[v].cover = ;
return;
}
int mid = (L + R)>>;
build(L,mid,v<<);
build(mid+,R,v<<|);
tree[v] = calc(tree[v<<],tree[v<<|],);
}
node query(int L,int R,int lt,int rt,int v) {
if(lt <= L && rt >= R) return tree[v];
int mid = (L + R)>>;
if(rt <= mid) return put(query(L,mid,lt,rt,v<<),tree[v].tag);
if(lt > mid) return put(query(mid+,R,lt,rt,v<<|),tree[v].tag);
return calc(query(L,mid,lt,rt,v<<),query(mid+,R,lt,rt,v<<|),tree[v].tag);
}
void cleartag(int v,int t) {
if(tree[v].maxtag < t) return;
if(tree[v].tag >= t) tree[v].tag = ;
if(tree[v].s > ) {
cleartag(v<<,t);
cleartag(v<<|,t);
}
if(tree[v].s == ) {
tree[v].sum = tree[v].maxtag = tree[v].maxv = tree[v].tag;
tree[v].cover = (tree[v].tag > );
} else tree[v] = calc(tree[v<<],tree[v<<|],tree[v].tag);
}
void update(int L,int R,int lt,int rt,int t,int v) {
if(tree[v].tag && tree[v].tag <= t) return;
if(lt <= L && rt >= R) {
cleartag(v,t);
tree[v].tag = t;
if(L == R) {
tree[v].sum = tree[v].tag = tree[v].maxv = tree[v].maxtag = t;
tree[v].cover = (tree[v].tag > );
} else tree[v] = calc(tree[v<<],tree[v<<|],t);
} else {
int mid = (L + R)>>;
if(rt <= mid) update(L,mid,lt,rt,t,v<<);
else if(lt > mid) update(mid+,R,lt,rt,t,v<<|);
else {
update(L,mid,lt,rt,t,v<<);
update(mid+,R,lt,rt,t,v<<|);
}
tree[v] = calc(tree[v<<],tree[v<<|],tree[v].tag);
}
}
int main() {
int kase,op,x,y,t;
scanf("%d",&kase);
while(kase--) {
scanf("%d%d",&n,&m);
build(,n,);
while(m--) {
scanf("%d%d%d",&op,&x,&y);
if(!op) {
scanf("%d",&t);
update(,n,x,y,t,);
} else if(op == ) printf("%d\n",query(,n,x,y,).maxv);
else printf("%I64d\n",query(,n,x,y,).sum);
}
}
return ;
}

哥终于搞清了,感谢 某岛 的代码

本题的做法有点类似于天龙八部里面虚竹那个下棋场景,死而后生

做法就是:每次更新一段区间的时候,把标记放到本区间,然后,我们要兵马未动,粮草先行

先去下面走一遭,统计下面有多少个不大于t,并且这些不大于t的元素的和

这样就能计算出当前区间的和了?不能?那么最大值呢?别逗了,当前区间的最大值肯定是t啦。

tag?要么就是0,要么就是区间的最大值。不是么?

你说这样都不超时真没天理?是的,我也是这么觉得的。。。每次都推到底,这还不超时。。。我也不知道分摊是如何分摊的

下面是搞清真相后写的另一份代码,代码内附有注释,我想这是你目前所能看到的最详细的解说了,毕竟中学生写的代码,可能是有代沟吧

 #include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = ;
struct node{
LL sum;
int cv,mx,tag;
//cv用来记录该区间有多少个数不大于t
//mx当然是记录区间的最大值
//tag是lazy标识啦,这个线段树常客
//sum...
}tree[maxn<<];
void pushup(int v){
tree[v].sum = tree[v<<].sum + tree[v<<|].sum;
tree[v].mx = max(tree[v<<].mx,tree[v<<|].mx);
tree[v].cv = tree[v<<].cv + tree[v<<|].cv;
}
int tmp;
void build(int lt,int rt,int v){
if(lt == rt){
scanf("%d",&tmp);
tree[v].sum = tree[v].mx = tree[v].tag = tmp;
tree[v].cv = ;
//cv记录的是不大于t的元素个数
return;
}
tree[v].tag = ;
int mid = (lt + rt)>>;
build(lt,mid,v<<);
build(mid+,rt,v<<|);
pushup(v);
}
void modify(int L,int R,int t,int v){
if(tree[v].tag && tree[v].tag <= t) return;
tree[v].tag = t;
//只有可能是tree[v].tag == 0
//因为前面calc的时候已经先行走了一遍
if(tree[v].cv != R - L + ){
//因为当前区间不大于t的元素不算全区间,所以还有比t大的
//大的要置成t,所以mx成了t
tree[v].mx = t;
tree[v].sum += (LL)t*(R - L + - tree[v].cv);
tree[v].cv = R - L + ;
//sum在alc以后 其实代表的是那些不大于t的元素之和
//现在把大于t的都改成t了,那么现在和是多少?
}
}
void pushdown(int L,int R,int v){
if(tree[v].tag){
int mid = (L + R)>>;
modify(L,mid,tree[v].tag,v<<);
modify(mid+,R,tree[v].tag,v<<|);
tree[v].tag = ;
}
}
void calc(int L,int R,int t,int v){
if(tree[v].mx < t) return;
if(tree[v].tag >= t) tree[v].tag = ;
if(L == R){
tree[v].sum = tree[v].mx = tree[v].tag;
tree[v].cv = tree[v].tag?:;
//记录当前不大于t的元素的个数以及他们的和
return;
}
pushdown(L,R,v);
int mid = (L + R)>>;
calc(L,mid,t,v<<);
calc(mid+,R,t,v<<|);
pushup(v);
}
void update(int L,int R,int lt,int rt,int t,int v){
if(tree[v].mx <= t) return;
if(lt <= L && rt >= R){
if(L == R){
tree[v].sum = tree[v].tag = tree[v].mx = t;
tree[v].cv = ;
//强行修改为t,毕竟此处是大于t的,如果不大于t前面return了
}else calc(L,R,t,v);//先行遍历到底,兵马未动,粮草先行
modify(L,R,t,v);
}else{
pushdown(L,R,v);
int mid = (L + R)>>;
if(lt <= mid) update(L,mid,lt,rt,t,v<<);
if(rt > mid) update(mid+,R,lt,rt,t,v<<|);
pushup(v);
}
}
int queryMax(int L,int R,int lt,int rt,int v){
if(lt <= L && rt >= R) return tree[v].mx;
int mid = (L + R)>>,mx = INT_MIN;
pushdown(L,R,v);
if(lt <= mid) mx = max(mx,queryMax(L,mid,lt,rt,v<<));
if(rt > mid) mx = max(mx,queryMax(mid+,R,lt,rt,v<<|));
pushup(v);
return mx;
}
LL querySum(int L,int R,int lt,int rt,int v){
if(lt <= L && rt >= R) return tree[v].sum;
int mid = (L + R)>>;
LL sum = ;
pushdown(L,R,v);
if(lt <= mid) sum += querySum(L,mid,lt,rt,v<<);
if(rt > mid) sum += querySum(mid+,R,lt,rt,v<<|);
pushup(v);
return sum;
}
int main(){
int kase,n,m,op,x,y,t;
scanf("%d",&kase);
while(kase--){
scanf("%d%d",&n,&m);
build(,n,);
while(m--){
scanf("%d%d%d",&op,&x,&y);
if(x > y) swap(x,y);
if(!op){
scanf("%d",&t);
update(,n,x,y,t,);
}else if(op == ) printf("%d\n",queryMax(,n,x,y,));
else printf("%I64d\n",querySum(,n,x,y,));
}
}
return ;
}

2015 Multi-University Training Contest 2 hdu 5306 Gorgeous Sequence的更多相关文章

  1. 2015 Multi-University Training Contest 6 hdu 5357 Easy Sequence

    Easy Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)T ...

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

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

  3. 2016 Multi-University Training Contest 10 || hdu 5860 Death Sequence(递推+单线约瑟夫问题)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5860 题目大意:给你n个人排成一列编号,每次杀第一个人第i×k+1个人一直杀到没的杀.然后 ...

  4. HDU 5306 Gorgeous Sequence

    如果维护max,sum,那么可以得到一个暴力方法,如果t>=max,那可以return,否则往下更新,显然超时. 在上面基础上,再维护一下次大值,与最大值的个数.这样一来,次大值<t< ...

  5. [HDU] 5306 Gorgeous Sequence [区间取min&求和&求max]

    题解: 线段树维护区间取min求和求max 维护最小值以及个数,次小值 标记清除时,分情况讨论 当lazy>max1 退出 当max1>lazy>max2(注意不要有等号) 更新 否 ...

  6. HDU - 5306 Gorgeous Sequence (吉司机线段树)

    题目链接 吉司机线段树裸题... #include<bits/stdc++.h> using namespace std; typedef long long ll; ,inf=0x3f3 ...

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

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

  8. 2015 Multi-University Training Contest 8 hdu 5390 tree

    tree Time Limit: 8000ms Memory Limit: 262144KB This problem will be judged on HDU. Original ID: 5390 ...

  9. 2015 Multi-University Training Contest 8 hdu 5383 Yu-Gi-Oh!

    Yu-Gi-Oh! Time Limit: 2000ms Memory Limit: 65536KB This problem will be judged on HDU. Original ID:  ...

随机推荐

  1. [USACO17JAN] Subsequence Reversal序列反转 (dfs+记忆化)

    题目大意:给你一个序列,你可以翻转任意一段子序列一次,求最长不下降子序列长度 tips:子序列可以不连续,但不能破坏在原序列中的顺序 观察数据范围,n<=50,很小,考虑dfs *dfs来跑区间 ...

  2. keepalived 和 heartbeat对比

    Keepalived使用的vrrp协议方式,虚拟路由冗余协议 (Virtual Router Redundancy Protocol,简称VRRP): Heartbeat是基于主机或网络的服务的高可用 ...

  3. php 文件加载方式

    两种加载文件的方式 include require 使用场景: 动态加载文件的时候,使用include,否则使用require. 示例: # 引入php文件--include方式 inlcude(&q ...

  4. 一行代码解决IE兼容性问题

    在网站开发中不免因为各种兼容问题苦恼,针对兼容问题,其实IE给出了解决方案Google也给出了解决方案百度也应用了这种方案去解决IE的兼容问题 百度源代码如下 <!Doctype html> ...

  5. 【转】 C#获取当前程序运行路径的方法集合

    [转] C#获取当前程序运行路径的方法集合 //获取当前进程的完整路径,包含文件名(进程名). string str = this.GetType().Assembly.Location; resul ...

  6. (转)彻底学会使用epoll(一)——ET模式实现分析

    注:之前写过两篇关于epoll实现的文章,但是感觉懂得了实现原理并不一定会使用,所以又决定写这一系列文章,希望能够对epoll有比较清楚的认识.是请大家转载务必注明出处,算是对我劳动成果的一点点尊重吧 ...

  7. angular-resource

    上一篇中讲到使用$http同服务器进行通信,但是功能上比较简单,angularjs还提供了另外一个可选的服务$resource,使用它可以非常方便的同支持restful的服务单进行数据交互. 安装 n ...

  8. win7创建webdav

    环境 win7+iis 构筑条件 存放路径:c:\Data 访问方式:192.168.x.xxx/webdav 用户名:yx 密码:yx 搭建顺序 1.添加iis.启动->控制面板->程序 ...

  9. jQuery fadeOut无效

    $(this).fadeOut("fast"), var nowele = $(this); nowele.fadeOut("fast")

  10. leetcode第一刷_Reverse Linked List II

    翻转链表绝对是终点项目,应该掌握的,这道题要求的是翻转一个区间内的节点.做法事实上非常相似,仅仅只是要注意判定開始是头的特殊情况,这样head要更新的,还有就是要把翻转之后的尾部下一个节点保存好,要么 ...