二维数点 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] << "\n";
    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 << "\n";
  }
}

猜你喜欢

转载自www.cnblogs.com/foreverpiano/p/9210553.html