二维数点 bzoj 3956 Count
Posted foreverpiano
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二维数点 bzoj 3956 Count相关的知识,希望对你有一定的参考价值。
https://www.lydsy.com/JudgeOnline/problem.php?id=3956
70分好像可以莫队
首先要发现答案是(mathcal O(n))的
Proof:
考虑一个点(a_k)对区间([l,r])的贡献
当且仅当(a_k=max(a_{l+1}, ... , a_{r-1}))且(a_l>a_k), (a_k<a_r)
于是对于一个点预处理一下((x, y))左边比他大的(x), 右边比他大的(y)
重复的数字的话 答案就只由最左边的更新就好了
统计答案主席树二维数点就好了
学习到了主席树的写法
先拷贝之前的根 然后在update时候每次新建一个节点
#include <bits/stdc++.h>
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "n"
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
x = 0; char c = getchar(); bool f = 0;
for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
for(int i = 1; i <= n; i ++)
cout << a[i] << " ";
puts("");
}
const int N = 3e5 + 233;
int n, m, type;
int a[N], q[N], top = 0;
int LP[N], RP[N], LT[N], rt[N];
vector<int> vec[N];
namespace seg {
#define mid (l + (r - l) / 2)
const int Segment_Size = N * 20;
int sum[Segment_Size], L[Segment_Size], R[Segment_Size];
int tot = 0;
inline void add(int &rt, int pre, int x, int l, int r) {
rt = ++ tot;
sum[rt] = sum[pre];
++ sum[rt];
if(l == r) return ;
if(x <= mid) R[rt] = R[pre], add(L[rt], L[pre], x, l, mid);
else L[rt] = L[pre], add(R[rt], R[pre], x, mid + 1, r);
}
inline int query(int v1, int v2, int ql, int qr, int l, int r) {
if(!v2) return 0;
if(ql == l && qr == r) return sum[v2] - sum[v1];
if(qr <= mid) return query(L[v1], L[v2], ql, qr, l, mid);
else if(ql > mid) return query(R[v1], R[v2], ql, qr, mid + 1, r);
else return query(L[v1], L[v2], ql, mid, l, mid) + query(R[v1], R[v2], mid + 1, qr, mid + 1, r);
}
inline void dfs(int rt, int l, int r) {
if(!rt || !sum[rt]) return ;
cout << l << " " << r << " " << sum[rt] << "
";
if(l == r) return ;
dfs(L[rt], l, mid);
dfs(R[rt], mid + 1, r);
}
#undef mid
}
int main(void) {
read(n); read(m); read(type);
for(int i = 1; i <= n; i ++)
read(a[i]);
// LP
top = 0;
for(int i = 1; i <= n; i ++) {
while(top && a[q[top]] <= a[i]) -- top;
if(top) LP[i] = q[top];
q[++ top] = i;
}
// RP
top = 0;
for(int i = n; i >= 1; i --) {
while(top && a[q[top]] <= a[i]) -- top;
if(top) RP[i] = q[top];
q[++ top] = i;
}
// LT
top = 0;
for(int i = 1; i <= n; i ++) {
while(top && a[q[top]] < a[i]) -- top;
if(top) LT[i] = q[top];
q[++ top] = i;
}
for(int i = 1; i <= n; i ++)
if(LP[i] && RP[i] && LP[i] == LT[i])
vec[LP[i]].push_back(RP[i]);
for(int i = 1; i <= n; i ++) {
rt[i] = rt[i - 1];
for(int k = 0; k < (int) vec[i].size(); k ++) {
seg::add(rt[i], rt[i], vec[i][k], 1, n);
}
}
int ans = 0;
for(int i = 1; i <= m; i ++) {
int l, r; read(l); read(r);
if(type) {
int u = (l + ans - 1) % n + 1;
int v = (r + ans - 1) % n + 1;
l = min(u, v);
r = max(u, v);
}
ans = seg::query(rt[l - 1], rt[r], l, r, 1, n);
ans += r - l;
cout << ans << "
";
}
}
以上是关于二维数点 bzoj 3956 Count的主要内容,如果未能解决你的问题,请参考以下文章