Welcome to t|

XiaoLe_MC

园龄:1年2个月粉丝:3关注:9

2024-08-16 19:18阅读: 54评论: 0推荐: 0

[题解] [HNOI2016] 序列

原题链接

题面

给定长度为 n 的序列:a1,a2,,an,记为 a[1:n]。类似地,a[l:r]1lrN )是指序列:al,al+1,,ar1,ar。若 1lstrn,则称 a[s:t]a[l:r] 的子序列。

现在有 q 个询问,每个询问给定两个数 lr1lrn,求 a[l:r] 的不同子序列的最小值之和。例如,给定序列
5,2,4,1,3,询问给定的两个数为 13,那么 a[1:3]6 个子序列 a[1:1],a[2:2],a[3:3],a[1:2],a[2:3],a[1:3],这 6 个子序列的最小值之和为 5+2+4+2+2+2=17

对于 100% 的数据, 1n,q100000|ai|109

解析

之前考试遇到过一道叫做“序序”的题,求的是子序列最大值和最小值的积的和。这道题是个丐版,实现起来还是比较简单的。

因为要求所有子序列的和,所以考虑猫树分治。就是把所有询问离线出来,然后挂到树上,找到树上的对应区间段。对于整条询问被这个区间段中点截断的左右两部分递归处理,然后左右合并的部分

蓝色部分对应的是查询区间,黑色的部分是猫树(?线段树),将查询下放到树上,可以发现被第一层区间的中点截成两半。

因为被截断的两个区间的答案和本次查询的答案是不影响的,所以被截断的两区间的答案可以继续下放递归处理。 而合并起来后的区间的答案需要在本层计算出来。考虑双指针。

imid 向左移,jmid+1 向右移,考虑由 ij 构成的区间的最小值来源于哪里。固定 i,在右边找到一个分界点 d,表示当 j[mid+1,d1] 时,最小值在左边区间取得,当 j[d,r] 时,最小值在右边区间取得。当 i 固定下来后,他的 d 也确定下来,那么就在 mid+1d1 的答案里加上 minl,在 dr 的答案里加上 minr。这个 minr 是右区间每个位置对应的最小值,不是固定的,区间修,区间查,需要用到线段树。因为不同的两种加值对应的系数也不同,所以需要开两棵线段树。并且随着 i 左移,d 的位置是单调向右的。所以单次维护复杂度 O(lenloglen)。总复杂度 nlog2n

code
#include<bits/stdc++.h>
using namespace std;
#ifdef _WIN32
#define getchar _getchar_nolock
#define putchar _putchar_nolock
#else
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif
template <typename T> inline void rd(T &x){
x = 0; int f = 1; char ch = getchar();
while(!isdigit(ch)){ if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) x = (x<<1) + (x<<3) + (ch^48), ch = getchar();
x *= f;
}
template <typename T> inline void wt(T x){
if(x < 0) putchar('-'), x = -x;
if(x / 10 > 0) wt(x / 10); putchar(x % 10 + '0');
}
#define int long long
#define ls (id << 1)
#define rs (id << 1 | 1)
constexpr int N = 1e5 + 5;
int n, q, a[N], ans[N], sum[N<<2], jmn[N], s[N];
struct Seg{ int l, r, ai; };
vector<Seg> spl[N<<2]; vector<int> ful[N<<2];
inline void insert(int id, int l, int r, int x, int y, int ai){
if(l > r) return ;
if(x <= l && r <= y) return (void)(ful[id].push_back(ai));
int mid = (l + r) >> 1;
if(x <= mid && mid < y) spl[id].push_back(Seg{max(l, x), min(r, y), ai});
if(x <= mid) insert(ls, l, mid, x, y, ai);
if(y > mid) insert(rs, mid+1, r, x, y, ai);
}
namespace ST{
struct node{ int l, r, sum[2], tag[2], val[2]; }t[N<<2];
inline void pushup(int id){
t[id].sum[0] = t[ls].sum[0] + t[rs].sum[0];
t[id].sum[1] = t[ls].sum[1] + t[rs].sum[1];
}
inline void addtag(int id, int k, int p){
t[id].tag[p] += k; t[id].sum[p] += k * t[id].val[p];
}
inline void pushdown(int id){
if(t[id].tag[0]) addtag(ls, t[id].tag[0], 0), addtag(rs, t[id].tag[0], 0);
if(t[id].tag[1]) addtag(ls, t[id].tag[1], 1), addtag(rs, t[id].tag[1], 1);
t[id].tag[0] = t[id].tag[1] = 0;
}
inline void build(int id, int l, int r){
t[id].l = l, t[id].r = r; t[id].val[0] = t[id].val[1] = 0;
t[id].sum[0] = t[id].sum[1] = t[id].tag[0] = t[id].tag[1] = 0;
if(l == r) return (void)(t[id].val[1] = jmn[l], t[id].val[0] = 1);
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid+1, r);
t[id].val[0] = t[ls].val[0] + t[rs].val[0];
t[id].val[1] = t[ls].val[1] + t[rs].val[1];
pushup(id);
}
inline void modify(int id, int l, int r, int k, int p){
if(l > r) return;
if(l <= t[id].l && t[id].r <= r) return addtag(id, k, p);
pushdown(id); int mid = (t[id].l + t[id].r) >> 1;
if(l <= mid) modify(ls, l, r, k, p);
if(r > mid) modify(rs, l, r, k, p);
pushup(id);
}
inline int query(int id, int l, int r){
if(l <= t[id].l && t[id].r <= r) return t[id].sum[0] + t[id].sum[1];
pushdown(id); int mid = t[ls].r, as = 0;
if(l <= mid) as += query(ls, l, r);
if(r > mid) as += query(rs, l, r);
return as;
}
}
inline void mao(int id, int l, int r){
if(l == r){
sum[id] = a[l];
for(int it : ful[id]) ans[it] += sum[id];
return;
}
int mid = (l + r) >> 1, imn = a[mid], j = mid + 1, k = 0;
sort(spl[id].begin(), spl[id].end(), [](const Seg x, const Seg y){ return x.l > y.l; });
jmn[mid + 1] = a[mid + 1]; s[mid + 1] = a[mid + 1];
for(int i=mid+2; i<=r; ++i) jmn[i] = min(a[i], jmn[i-1]);
ST::build(1, mid + 1, r);
for(int i=mid; i>=l ;--i){
imn = min(imn, a[i]); while(j <= r && jmn[j] > imn) ++j;
ST::modify(1, mid+1, j - 1, imn, 0), ST::modify(1, j, r, 1, 1);
while(k < (int)spl[id].size() && spl[id][k].l == i) ans[spl[id][k].ai] += ST::query(1, mid+1, spl[id][k].r), ++k;
}
sum[id] += ST::query(1, mid+1, r);
mao(ls, l, mid), mao(rs, mid+1, r);
sum[id] += sum[ls] + sum[rs];
for(int it : ful[id]) ans[it] += sum[id];
}
signed main(){
rd(n), rd(q);
for(int i=1; i<=n; ++i) rd(a[i]);
for(int i=1, x, y; i<=q; ++i) rd(x), rd(y), insert(1, 1, n, x, y, i);
mao(1, 1, n); for(int i=1; i<=q; ++i) wt(ans[i]), putchar('\n');
return 0;
}

本文作者:XiaoLe_MC

本文链接:https://www.cnblogs.com/xiaolemc/p/18363495

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   XiaoLe_MC  阅读(54)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起