莫队+st表

据说这是经典问题,但是我不会。。。

问题在于莫队怎么算贡献,每次移动一个位置,现在为[l,r],那么就增加了[l-1,r),r的贡献,怎么算呢?我们预处理fl,fr,fl[i]表示以i为开头的前缀和,fr表示以i为结尾的后缀和,这个东西能够相减,但也不是完全满足

每次我们计算贡献的时候,设最小值的位置为p,那么对于右端点来说,贡献就是fr[r]-fr[p]+(p - l + 1) * a[p],这也是因为不完全满足可减性,因为求前缀和是fr[i]=(i - l[i] + 1) * a[i] + fr[l[i]-1],那么满足可减性是在每个l[i]的时候可以减,又因为p作为最小值肯定是处于一个l的位置,那么就能减了,而到l的贡献就是p作为最小值。

理解得还不是很透彻 我一直以为我的单调栈是左闭右闭的,竟然是左开右闭的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + ;
int n, m, block, l = , r, top;
ll sum;
int st[N], Log[N], f[N][], L[N], R[N];
ll fl[N], fr[N], a[N], ans[N];
struct query {
int l, r, id;
bool friend operator < (const query &a, const query &b) {
return (a.l - ) / block == (b.l - ) / block ? a.r < b.r : (a.l - ) / block < (b.l - ) / block;
}
} q[N];
inline int rd()
{
int x = , f = ; char c = getchar();
while(c < '' || c > '') { if(c == '-') f = -; c = getchar(); }
while(c >= '' && c <= '') { x = x * + c - ''; c = getchar(); }
return x * f;
}
int Min(int x, int y)
{
return a[x] < a[y] ? x : y;
}
int rmq(int l, int r)
{
int x = Log[r - l + ];
return Min(f[l][x], f[r - ( << x) + ][x]);
}
void addl(int l, int r, ll f)
{
int p = rmq(l, r);
sum += f * (fl[l] - fl[p] + a[p] * (ll)(r - p + ));
}
void addr(int l, int r, ll f)
{
int p = rmq(l, r);
sum += f * (fr[r] - fr[p] + a[p] * (ll)(p - l + ));
}
int main()
{
n = rd();
m = rd();
block = sqrt(n);
for(int i = ; i <= n; ++i)
{
a[i] = rd();
f[i][] = i;
}
for(int i = ; i <= n; ++i) Log[i] = Log[i >> ] + ;
for(int j = ; j <= ; ++j)
for(int i = ; i + ( << j) <= n + ; ++i)
f[i][j] = Min(f[i][j - ], f[i + ( << (j - ))][j - ]);
for(int i = ; i <= m; ++i)
{
q[i].l = rd();
q[i].r = rd();
q[i].id = i;
}
sort(q + , q + m + );
for(int i = ; i <= n; ++i)
{
L[i] = R[i] = i;
while(top && a[st[top]] > a[i])
{
R[st[top - ]] = R[st[top]];
L[i] = L[st[top]];
--top;
}
st[++top] = i;
}
while(top)
{
R[st[top - ]] = R[st[top]];
--top;
}
for(int i = ; i <= n; ++i) fr[i] = fr[L[i] - ] + (ll)(i - L[i] + ) * a[i];
for(int i = n; i; --i) fl[i] = fl[R[i] + ] + (ll)(R[i] - i + ) * a[i];
l = ;
r = ;
for(int i = ; i <= m; ++i)
{
while(r < q[i].r) addr(l, ++r, );
while(r > q[i].r) addr(l, r--, -);
while(l < q[i].l) addl(l++, r, -);
while(l > q[i].l) addl(--l, r, );
ans[q[i].id] = sum;
}
for(int i = ; i <= m; ++i) printf("%lld\n", ans[i]);
return ;
}

莫队一定要先动r

最新文章

  1. Netty构建分布式消息队列实现原理浅析
  2. XE5 修复 安卓 输入法隐藏 后 无法退出的问题 3.2
  3. Unity 逐步旋转
  4. mongod 命令执行发现已经有进程在运行mongod数据库--errno:48 Address already in use for socket: 0.0.0.0:27017
  5. SQL语句的简单使用
  6. SQL:with ties
  7. java中的clone
  8. SwapEffect 枚举(定义交换效果)
  9. webapp框架—学习AngularUI1(demo折腾)
  10. poj 2074 Line of Sight 计算几何
  11. 同形异义字:看我如何拿到TaoBao.com的解析权
  12. 如何关闭常见浏览器的 HSTS 功能
  13. Nginx 参数配置相关
  14. 树莓派2B+安装Debain操作系统
  15. 02: CMDB设计思路
  16. Hibernate_day01讲义_使用Hibernate完成对CRM系统中客户管理的DAO中的CRUD的操作
  17. SDL检查
  18. 15-js提交表单的简单检测实例
  19. Oracle sql语句中(+)作用
  20. 每一个软件开发人员绝对必须掌握的关于 Unicode 和字符集的最基础的知识

热门文章

  1. Logistic Regression 笔记与理解
  2. KVM技术
  3. MacBook Pro使用初体验之Mac快捷键汇总(持续更新中)
  4. WPF自定义Popup和弹出菜单
  5. 继续聊WPF——获取ComboBox中绑定的值
  6. SQL还原数据库后,数据库显示受限制用户解决方法
  7. live555 RTSP推送到Darwin出现404错误的解决
  8. 面向资源操作的http请求
  9. Learning Scrapy 中文版翻译 第二章
  10. java中两字符串比较--compareTo方法