首页 > 其他分享 >CF1270H Number of Components 题解

CF1270H Number of Components 题解

时间:2024-09-23 15:14:07浏览次数:10  
标签:10 连通 le int 题解 Number kMaxN CF1270H 数组

Description

给一个长度为 \(n\) 的数组 \(a\),\(a\) 中的元素两两不同。

对于每个数对 \((i,j)(i<j)\),若 \(a_i<a_j\),则让 \(i\) 向 \(j\) 连一条边。求图中连通块个数。

支持 \(q\) 次修改数组某个位置的值,每次修改后输出图中连通块个数。

\(n,q\le 5\times 10^5,1\le a_i\le 10^6\),保证任意时刻数组中元素两两不同。

Solution

考虑怎么求一个序列有几个连通块。

首先有个性质是每个连通块一定是一个区间,证明就考虑钦定 \(i<k<j\) 且 \(i\) 和 \(j\) 连通。如果 \(a_i<a_j\),则 \(a_i<a_k\) 和 \(a_k<a_j\) 必定满足至少一个。

如果 \(a_i>a_j\),由于 \(i,j\) 连通,所以一定存在 \(x<i\) 且 \(a_i>a_j>a_x\) 或 \(x>j\) 且 \(a_x>a_i>a_j\)。这样就规约到了 \(a_i<a_j\) 的情况。故结论得证。

所以连通块数就是满足 \(\min_{i=1}^{k}{a_i}>\max_{i=k+1}^{n}{a_i}\) 的 \(k\) 的数量。

考虑枚举前缀的最小值 \(x\),将 \(a\) 数组中大于等于 \(x\) 的位置设成 \(1\),小于 \(x\) 的位置设成 \(0\),则合法的 \(x\) 一定满足 \(01\) 序列为 \(11110000\) 的形式,即 \(10\) 的出现次数为 \(1\)。

设 \(cnt_x\) 表示 \(x\) 的 \(01\) 序列中 \(10\) 的出现次数。于是题目转化为求对于所有在 \(a\) 数组中出现了的 \(x\) 中 \(cnt_x=1\) 的 \(x\) 的数量,维护一个值域的线段树即可。

时间复杂度:\(O\left((n+q)\log n\right)\)。

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 1e6 + 5;

int n, q, m;
int a[kMaxN], pos[kMaxN], x[kMaxN], unq[kMaxN];

struct SGT {
  int mi[kMaxN * 4], tag[kMaxN * 4], tot[kMaxN * 4], cnt[kMaxN * 4];

  void pushup(int x) {
    mi[x] = std::min(tot[x << 1] ? mi[x << 1] : 1e9, tot[x << 1 | 1] ? mi[x << 1 | 1] : 1e9);
    tot[x] = tot[x << 1] + tot[x << 1 | 1];
    cnt[x] = 0;
    if (tot[x << 1] && mi[x] == mi[x << 1]) cnt[x] += cnt[x << 1];
    if (tot[x << 1 | 1] && mi[x] == mi[x << 1 | 1]) cnt[x] += cnt[x << 1 | 1];
  }

  void addtag(int x, int v) {
    mi[x] += v, tag[x] += v;
  }

  void pushdown(int x) {
    if (tag[x])
      addtag(x << 1, tag[x]), addtag(x << 1 | 1, tag[x]), tag[x] = 0;
  }

  void build(int x, int l, int r) {
    if (l == r) return void(cnt[x] = 1);
    int mid = (l + r) >> 1;
    build(x << 1, l, mid), build(x << 1 | 1, mid + 1, r);
    pushup(x);
  }

  void update1(int x, int l, int r, int ql, int v) {
    if (l == r) return void(tot[x] = v);
    pushdown(x);
    int mid = (l + r) >> 1;
    if (ql <= mid) update1(x << 1, l, mid, ql, v);
    else update1(x << 1 | 1, mid + 1, r, ql, v);
    pushup(x);
  }

  void update2(int x, int l, int r, int ql, int qr, int v) {
    if (l > qr || r < ql) return;
    else if (l >= ql && r <= qr) return addtag(x, v);
    pushdown(x);
    int mid = (l + r) >> 1;
    update2(x << 1, l, mid, ql, qr, v), update2(x << 1 | 1, mid + 1, r, ql, qr, v);
    pushup(x);
  }

  int query() { return tot[1] && mi[1] == 1 ? cnt[1] : 0; }
} sgt;

void discrete() {
  for (int i = 0; i <= n + 1; ++i) unq[++m] = a[i];
  for (int i = 1; i <= q; ++i) unq[++m] = x[i];
  std::sort(unq + 1, unq + 1 + m);
  m = std::unique(unq + 1, unq + 1 + m) - unq;

  for (int i = 0; i <= n + 1; ++i)
    a[i] = std::lower_bound(unq + 1, unq + 1 + m, a[i]) - unq;
  for (int i = 1; i <= q; ++i)
    x[i] = std::lower_bound(unq + 1, unq + 1 + m, x[i]) - unq;
}

void update(int x, int y, int v) {
  if (x > y) sgt.update2(1, 1, m, y + 1, x, v);
}

void dickdreamer() {
  std::cin >> n >> q;
  a[0] = 1e9, a[n + 1] = -1e9;
  for (int i = 1; i <= n; ++i) std::cin >> a[i];
  for (int i = 1; i <= q; ++i) std::cin >> pos[i] >> x[i];
  discrete();
  sgt.build(1, 1, m);
  for (int i = 1; i <= n; ++i) sgt.update1(1, 1, m, a[i], 1);
  for (int i = 0; i <= n; ++i) update(a[i], a[i + 1], 1);
  for (int i = 1; i <= q; ++i) {
    update(a[pos[i] - 1], a[pos[i]], -1), update(a[pos[i]], a[pos[i] + 1], -1);
    sgt.update1(1, 1, m, a[pos[i]], 0);
    a[pos[i]] = x[i];
    update(a[pos[i] - 1], a[pos[i]], 1), update(a[pos[i]], a[pos[i] + 1], 1);
    sgt.update1(1, 1, m, a[pos[i]], 1);
    std::cout << sgt.query() << '\n';
  }
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  // std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:10,连通,le,int,题解,Number,kMaxN,CF1270H,数组
From: https://www.cnblogs.com/Scarab/p/18427107

相关文章

  • 2024ICPC网络赛第二场题解(部分)
    前言这场相对作用大一点,最后顶着队友的怀疑压力乱搞出了C,但是后面看题解发现似乎是数据弱了跑过去,其实复杂度是队友分析的那样,是不正确的,但是毕竟是打名额的比赛,过了就是过了,这里分享一下C题的乱搞做法,以及其他题的我们队赛时代码。下面的顺序按过题顺序(也差不多是难度递增顺序)......
  • 网站程序打不开数据库错误等常见问题解决方法
    当遇到网站打不开或者数据库错误等问题时,可以按照以下步骤来诊断并解决问题:检查网站根目录:如果上传数据后显示“主机开设成功!”或“恭喜,lanmp安装成功!”,这通常是因为服务器默认放置了一个index.htm文件。此时应检查wwwroot目录内是否有自己的程序文件,并考虑删除默认的index.h......
  • 题解:AT_arc184_a [ARC184A] Appraiser
    本质上还是官方题解的分组并利用\(M\)不大的思路。询问次数\(Q\)离最简单的每个扫一遍就可以知道答案的做法少了\(50\)次。我们考虑如何减少这个次数。首先你可以发现一次询问可以覆盖到两个数,也就是说所有的数都被覆盖时只需要询问\(500\)次。我们考虑把不同的对拉出......
  • 网站打不开数据库错误等常见问题解决方法
    当遇到网站打不开且出现数据库错误等问题时,可以采取以下步骤进行排查和解决:检查默认页面:如果网站显示“主机开设成功!”或者“恭喜,lanmp安装成功!”这样的信息,这可能是服务器默认放置的页面。检查wwwroot目录下是否有自己的程序文件,如果没有,上传正确的文件,并删除默认的index.ht......
  • [ABC371F] Takahashi in Narrow Road 题解
    洛谷题目链接Atcoder题目链接前言这道题我赛时想到了正解并打了出来,然后因为把\(l\)打成了\(1\)导致WA\(\times23\),然后又没场切六道题(悲。然后赛后有人说正解是珂朵莉树/线段树,然而我是珂朵莉树\(+\)线段树,呵。题意数轴上有\(n\)个人,第\(i\)个人初始在\(X_i\)处,每一次操作......
  • CF1239E Turtle 题解
    Description一只乌龟从\(2\timesn\)的棋盘的左上角走到右下角,只能往下或往右,需要给出一种方案来分配\(2n\)个数字使得乌龟走过的路径上的数之和的最大值最小。\(2\leqn\leq25,0\leqa_{1,i},a_{2,i}\leq5\times10^4\)。Solution设\(pre_{i}=\sum_{j=1}^{i}{a_{1,i}......
  • P5975 photo 题解
    Solution先离散化,记\(f(l,r,p)\)为覆盖了\([l,r]\)区间内纵坐标\(\gep\)的点最少矩形个数。则:\[f(l,r,p)=\min(f(l,r,p),f(l,mid,p)+f(mid+1,r,p))\]\[f(l,r,p)=\min(f(l,r,p),f(l,r,res)+1)\]令\(h\)为用面积为\(S\)的矩形去覆盖\([l,r]\)区间的高度,即\(S/(r......
  • P9192 Pareidolia 题解
    Statement给串\(t\),定义\(B(s)\)为\(s\)删一些字符后能出现最多多少个bessie,\(A(t)\)表示对\(t\)的所有子串\(s\)求\(B(s)\)的和,有\(q\)次单点修改,每次改完输出\(B(s)\).Solution动态dp,但是带矩乘\(6^3\)常数,不好.还是考虑分治咋做.现在有区间\([l,mid],......
  • P3703 树点涂色 题解
    Statement树,每个点有一个颜色,初始每个点颜色互不相同到根链涂上新颜色链颜色数\(u\)子树内点\(v\)到根路径的最多颜色数Solution首先,相同颜色的点一定构成一条从下往上的链考虑LCT,维护一个性质:一条实链的点的颜色相同.于是\(u\)到根的颜色数\(=\)\(u\)到根的虚......
  • 最长公共子串 题解
    StatementQ7.1.2.4,时限4s给一个串,定义\(\mathrm{LCS}\)为最长公共子串长度,\(q\)次询问,每次给出\(l,r\),求\[\operatorname{xor}_{i=1}^{r-l+1}\{i+\mathrm{LCS}(S[l,l+i-1],S[l+i-1,r])\}\]\(n\le10^5,q\le30\)Solutiontag:SA,线段树维护分治结构,orzhunction题目就是......