线段树+矩阵
我来发一篇博客证明我还活着
题目要求的区间所有子区间的最小值之和不太容易合并,因此直接上数据结构不好做。
考虑离线做法。把所有询问右端点排序。
从左到右扫描整个序列,扫描到
i
时维护所有
如何随着
然后大概卡了一个中午的常数吧。
#include<cstdio>
#include<vector>
#include<cstring>
#define N 100005
using namespace std;
int read()
{
int r = 0, p = 0; char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) c == '-' ? p = 1 : 0;
for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar());
return p?-r:r;
}
namespace runzhe2000
{
typedef long long ll;
const int INF = 1<<30;
int n, q, a[N], sta[N], stacnt, nocnt;
ll ans[N];
struct que{int id, l; que *next;}node[N], *last[N];
struct matrix
{
ll a[3][3];
matrix(){memset(a,0,sizeof(a));}
matrix operator * (matrix &that)
{
matrix r;
for(int i = 0; i < 3; i++)
{
ll *rai = r.a[i], *ai = a[i];
for(int j = 0; j < 3; j++)
for(int k = 0; k < 3; k++)
rai[j] += ai[k]*that.a[k][j];
}
return r;
}
}I, mat_v, mat_sum;
struct seg
{
matrix val, tag;
int need;
}t[N*4];
void pushdown(int x)
{
if(!t[x].need)return; t[x].need = 0;
seg *ls = &t[x<<1], *rs = &t[x<<1|1];
ls->val = ls->val * t[x].tag;
ls->tag = ls->tag * t[x].tag;
rs->val = rs->val * t[x].tag;
rs->tag = rs->tag * t[x].tag;
ls->need = rs->need = 1;
t[x].tag = I;
}
void pushup(int x)
{
ll *a0 = t[x].val.a[0], *a0l = t[x<<1].val.a[0], *a0r = t[x<<1|1].val.a[0];
for(int i = 0; i < 3; i++) a0[i] = a0l[i] + a0r[i];
}
void build(int x, int l, int r)
{
t[x].val.a[0][2] = r-l+1; t[x].tag = I; t[x].need = 0;
if(l == r) return; int mid = (l+r)>>1;
build(x<<1,l,mid); build(x<<1|1,mid+1,r);
}
void modi(int x, int l, int r, int ql, int qr, matrix &val)
{
if(ql <= l && r <= qr)
{
t[x].need = 1;
t[x].tag = t[x].tag * val;
t[x].val = t[x].val * val;
return;
}
pushdown(x);
int mid = (l+r)>>1;
if(ql <= mid) modi(x<<1,l,mid,ql,qr,val);
if(mid < qr) modi(x<<1|1,mid+1,r,ql,qr,val);
pushup(x);
}
ll query(int x, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr) return t[x].val.a[0][0];
int mid = (l+r)>>1; ll ret = 0;
pushdown(x);
if(ql <= mid) ret += query(x<<1,l,mid,ql,qr);
if(mid < qr) ret += query(x<<1|1,mid+1,r,ql,qr);
return ret;
}
void main()
{
n = read(), q = read();
for(int i = 1; i <= n; i++) a[i] = read();
for(int i = 0; i < 3; i++) I.a[i][i] = mat_sum.a[i][i] = 1;
mat_sum.a[1][0] = 1;
mat_v.a[0][0] = mat_v.a[2][2] = 1;
build(1,1,n);
for(int i = 1; i <= q; i++)
{
int l = read(), r = read();
node[++nocnt] = (que){i,l,last[r]};
last[r] = &node[nocnt];
}
a[0] = -INF;
for(int i = 1; i <= n; i++)
{
for(; a[sta[stacnt]] >= a[i]; stacnt--);
mat_v.a[2][1] = a[i];
modi(1,1,n,sta[stacnt]+1,i,mat_v);
modi(1,1,n,1,i,mat_sum);
sta[++stacnt] = i;
for(que *j = last[i]; j; j = j->next)
{
ans[j->id] = query(1,1,n,j->l,i);
}
}
for(int i = 1; i <= q; i++) printf("%lld\n",ans[i]);
}
}
int main()
{
runzhe2000::main();
}