【BZOJ4262】Sum 单调栈+线段树
【BZOJ4262】Sum
Description
Input
Output
Sample Input
1 3 5 7
2 4 6 8
1 1 9 9
9 9 1 1
Sample Output
9025304064
1065645568
0
HINT
1<=t<=40000,1<=L1<R1<=10^5,1<=L2<=R2<=10^5
题解:我们分开考虑max和pre的情况。我们将max(i...j)视为二维平面上点(i,j)的权值,处理出每个数左边第一个比它大的数,然后这个数的贡献区间可以就看成一个矩形(或三角形),而询问就变成了求平面上一个矩形区域的权值和。可以用线段树来搞。
不过线段树维护历史总和还真是不容易,打标记的部分还是好好说说吧。
维护三个值:v代表当前的区间和,s代表历史的v之和,l代表区间长度。
维护四个标记:a,b,c,d,代表标记生效后,v=a*v+b*l,s=s+c*v+d*l。
关键在于标记如何合并。假如我们要将x和y的标记合并成z。
a:显然z.a=x.a*y.a即可。
b:先要*=y.a,还要+=y.b。
c:+=x.a*y.c。
d:先要+=y.d,还要+=x.b*y.c。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=100010;
typedef long long ll;
struct Tag
{
ll a,b,c,d;
Tag () {a=1,b=c=d=0;}
Tag (ll A,ll B,ll C,ll D) {a=A,b=B,c=C,d=D;}
Tag operator + (const Tag &x) const {return Tag(a*x.a,b*x.a+x.b,a*x.c+c,d+b*x.c+x.d);}
};
struct node
{
ll v,s,l;
Tag t;
node () {v=s=l=0,t=Tag();}
node (ll a,ll b,ll c,Tag d) {v=a,s=b,l=c,t=d;}
inline void add(Tag x)
{
s=s+v*x.c+l*x.d,v=v*x.a+l*x.b,t=t+x;
}
node operator + (const node &a) const
{
return node(v+a.v,s+a.s,l+a.l,Tag());
}
}s[maxn<<2];
int m,n,top;
ll ans[maxn],v[maxn];
int st[maxn],pre[maxn];
struct QUERY
{
int x,l,r,org,k;
}q[maxn];
bool cmp(const QUERY &a,const QUERY &b)
{
return a.x<b.x;
}
inline void pushdown(int x)
{
if(s[x].t.a!=1||s[x].t.b||s[x].t.c||s[x].t.d) s[lson].add(s[x].t),s[rson].add(s[x].t),s[x].t=Tag();
}
void build(int l,int r,int x)
{
if(l==r)
{
s[x]=node(),s[x].l=1;
return ;
}
int mid=(l+r)>>1;
build(l,mid,lson),build(mid+1,r,rson);
s[x]=s[lson]+s[rson];
}
void updata(int l,int r,int x,int a,int b,Tag t)
{
if(a>b) return ;
if(a<=l&&r<=b)
{
s[x].add(t);
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,lson,a,b,t);
if(b>mid) updata(mid+1,r,rson,a,b,t);
s[x]=s[lson]+s[rson];
}
node query(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b) return s[x];
pushdown(x);
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,lson,a,b);
if(a>mid) return query(mid+1,r,rson,a,b);
return query(l,mid,lson,a,b)+query(mid+1,r,rson,a,b);
}
void work(ll flag)
{
int i,j;
build(1,n,1);
for(j=1;j<=2*m&&!q[j].x;j++);
for(i=1;i<=n;i++)
{
updata(1,n,1,pre[i],i,Tag(0,v[i],0,0)),s[1].add(Tag(1,0,1,0));
for(;j<=2*m&&q[j].x==i;j++) ans[q[j].org]+=flag*q[j].k*query(1,n,1,q[j].l,q[j].r).s;
}
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int main()
{
m=rd();
int i;
ll t1=1,t2=1;
for(i=1;i<=m;i++) q[i].l=q[i+m].l=rd(),q[i].r=q[i+m].r=rd(),q[i].x=rd()-1,q[i+m].x=rd(),
n=max(n,q[i+m].x),q[i].k=-1,q[i+m].k=1,q[i].org=q[i+m].org=i;
for(i=1;i<=n;i++) t1=t1*1023%1000000000,t2=t2*1025%1000000000,v[i]=t1^t2;
sort(q+1,q+2*m+1,cmp);
for(i=1;i<=n;i++)
{
while(top&&v[st[top]]>=v[i]) top--;
pre[i]=st[top]+1,st[++top]=i;
}
work(-1);
for(top=0,i=1;i<=n;i++)
{
while(top&&v[st[top]]<=v[i]) top--;
pre[i]=st[top]+1,st[++top]=i;
}
work(1);
for(i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}
【BZOJ4262】Sum 单调栈+线段树的更多相关文章
- 洛谷P4198 楼房重建 单调栈+线段树
正解:单调栈+线段树 解题报告: 传送门! 首先考虑不修改的话就是个单调栈板子题昂,这个就是 然后这题的话,,,我怎么记得之前考试好像有次考到了类似的题目昂,,,?反正我总觉着这方法似曾相识的样子,, ...
- 2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树)
2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树) 传送门:https://nanti.jisuanke.com/t/41296 题意: 给一个数列A 问在数列A中有多 ...
- The Preliminary Contest for ICPC China Nanchang National Invitational I. Max answer (单调栈+线段树)
题目链接:https://nanti.jisuanke.com/t/38228 题目大意:一个区间的值等于该区间的和乘以区间的最小值.给出一个含有n个数的序列(序列的值有正有负),找到该序列的区间最大 ...
- 2019南昌网络赛-I(单调栈+线段树)
题目链接:https://nanti.jisuanke.com/t/38228 题意:定义一段区间的值为该区间的和×该区间的最小值,求给定数组的最大的区间值. 思路:比赛时还不会线段树,和队友在这题上 ...
- 网络赛 I题 Max answer 单调栈+线段树
题目链接:https://nanti.jisuanke.com/t/38228 题意:在给出的序列里面找一个区间,使区间最小值乘以区间和得到的值最大,输出这个最大值. 思路:我们枚举每一个数字,假设是 ...
- 南昌邀请赛I.Max answer 单调栈+线段树
题目链接:https://nanti.jisuanke.com/t/38228 Alice has a magic array. She suggests that the value of a in ...
- 南昌网络赛 I. Max answer (单调栈 + 线段树)
https://nanti.jisuanke.com/t/38228 题意给你一个序列,对于每个连续子区间,有一个价值,等与这个区间和×区间最小值,求所有子区间的最大价值是多少. 分析:我们先用单调栈 ...
- 2019ICPC南昌邀请赛网络赛 I. Max answer (单调栈+线段树/笛卡尔树)
题目链接 题意:求一个序列的最大的(区间最小值*区间和) 线段树做法:用单调栈求出每个数两边比它大的左右边界,然后用线段树求出每段区间的和sum.最小前缀lsum.最小后缀rsum,枚举每个数a[i] ...
- 2018宁夏邀请赛 Continuous Intervals(单调栈 线段树
https://vjudge.net/problem/Gym-102222L 题意:给你n个数的序列,让判断有几个区间满足排完序后相邻两数差都不大于1. 题解:对于一个区间 [L,R],记最大值为 m ...
随机推荐
- mysql常见数据提示 mysql报错提示大全
错误代码和消息 目录 B.1. 服务器错误代码和消息 B.2. 客户端错误代码和消息 本章列出了当你用任何主机语言调用MySQL时可能出现的错误.首先列出了服务器错误消息.其次列出了客户端程序消息. ...
- Atitit.c# .net 3.5 4.0 4.5 5.0 6.0各个版本新特性战略规划总结
Atitit.c# .net 3.5 4.0 各个版本新特性战略规划总结 1. --------------.Net Framework版本同CLR版本的关系1 2. paip.----------- ...
- windows gvim插入当前时间
:nnoremap <F5> "=strftime("%c")<CR>P :inoremap <F5> <C-R>=str ...
- [k8s]metricbeat的kubernetes模块&kube-metric模块
正确姿势启动metricbeat metricbeat.modules: - module: system metricsets: - cpu - filesystem - memory - netw ...
- C/C++:C++伪函数
C++伪函数: 所谓的伪函数.就是说它不是一个真正的函数,而是一个类或者说是一个结构体. <span style="font-size:18px;"> #include ...
- 算法5-6:Kd树
问题 给定一系列的点.和一个矩形.求矩形中包括的点的数量. 解答 这个问题能够通过建立矩阵来进行求解.首先将一个空间切割成矩阵,将点放置在相应的格子中.再计算矩形覆盖的格子.再推断格子中的点是否包括在 ...
- Linux下让进程在后台可靠运行的几种方法
想让进程在断开连接后依然保持运行?如果该进程已经开始运行了该如何补救? 如果有大量这类需求如何简化操作? 我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一 ...
- 进程控制函数(2)-setpgid() 修改当前进程的进程组ID
定义:int setpgid(pid_t pid,pid_t pgid); 表头文件:#include<unistd.h> 说明:setpgid()将参数pid 指定进程所属的组识别码设为 ...
- 管道相关函数(1)-pipe
定义: int pipe(int filedes[2]); 表头文件: #include<unistd.h> 说明: pipe()会建立管道, 并将文件描述词由参数filedes数组返回. ...
- 0063 MyBatis入门示例
MyBatis是一个"半自动化"的ORM框架,ORM即Object/Relation Mapping,对象关系映射,是面向对象编程语言跟关系型数据库的桥梁,将编程语言对Java实体 ...