首页 > 其他分享 >CF997E Good Subsegments

CF997E Good Subsegments

时间:2023-07-20 18:45:02浏览次数:52  
标签:CF997E rs int mn tr Good Subsegments ls ct

简单题,不知道为啥和弱化版一个 Difficulty。

考虑弱化怎么做。

区间 \([l,r]\) 中的数是连续的,当且仅当区间最大值 \(\max\) 减去区间最小值 \(\min\) 为 \(r-l\),即 \(\max-\min=r-l\)。

考虑扫描线,固定右端点 \(r\),统计每个左端点的贡献。

由于 \(S(l,r)=\text{max}-\text{min}+l-r\ge 0\),考虑维护每个 \(l\) 的 \(S\) 值。有贡献的左端点即 \(S(l)=0\),线段树维护区间最小值的个数即可。

考虑右端点 \(r\) 移动,然后这个 \(\max\) 和 \(\min\) 可以用两个单调栈维护,动态修改 \(S\) 值,这很经典。然后你会弱化版了。


回到这题,还是考虑扫描线,但是固定右端点 \(r\) 的时候,可能可以贡献到 \(q_r\in[r,n]\) 的询问,不太好做。

可以再维护一个标记 \(tm\),表示当前区间左端点应该向答案贡献多少次;由这个标记可以计算出当前区间的所有左端点对答案的历史贡献总和 \(sum\)。

注意到修改最小值时下放了 \(tm\) 标记,所以每次标记下放 \(tm\) 时对应的最小值一定是原来的最小值。

注意到有贡献的 \(r\) 在 \([ql,qr]\) 之间,贡献的 \(l\le r\),所以取 \([ql,qr]\) 左端点的历史贡献总和即可。

复杂度还是 \(O(n\log n)\)。

#include <bits/stdc++.h>
#define ll long long
using namespace std;

namespace vbzIO {
	char ibuf[(1 << 20) + 1], *iS, *iT;
	#if ONLINE_JUDGE
	#define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
	#else
	#define gh() getchar()
	#endif
	#define rd read
	#define wr write
	#define pc putchar
	#define pi pair<int, int>
	#define mp make_pair
	#define fi first
	#define se second
	#define pb push_back
	#define ins insert
	#define era erase
	inline int read () {
		char ch = gh();
		int x = 0;
		bool t = 0;
		while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
		while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
		return t ? ~(x - 1) : x;
	}
	inline void write(ll x) {
		if (x < 0) {
			x = ~(x - 1);
			putchar('-');
		}
		if (x > 9)
			write(x / 10);
		putchar(x % 10 + '0');
	}
}
using vbzIO::read;
using vbzIO::write;

const int inf = 1e9;
const int N = 3e5 + 300;
struct seg { int mn, ct, tg, tm; ll sum; seg () { mn = inf; } } tr[N << 2];
int n, m, a[N], tp[2], st[N][2];
vector<pi> q[N];
ll ans[N];

#define ls x << 1
#define rs x << 1 | 1
#define mid ((l + r) >> 1)
void pushup(int x) {
	if (tr[ls].mn == tr[rs].mn) tr[x].mn = tr[ls].mn, tr[x].ct = tr[ls].ct + tr[rs].ct;
	else if (tr[ls].mn < tr[rs].mn) tr[x].mn = tr[ls].mn, tr[x].ct = tr[ls].ct;
	else tr[x].mn = tr[rs].mn, tr[x].ct = tr[rs].ct;
	tr[x].sum = tr[ls].sum + tr[rs].sum;
}

void pushtg(int x, int c) { tr[x].mn += c, tr[x].tg += c; }
void pushtm(int x, int c) { tr[x].sum += 1ll * tr[x].ct * c, tr[x].tm += c; }
void pushdown(int x) {
	if (tr[x].tg) {
		pushtg(ls, tr[x].tg), pushtg(rs, tr[x].tg);
		tr[x].tg = 0;
	}
	if (tr[x].tm) {
		if (tr[ls].mn == tr[x].mn) pushtm(ls, tr[x].tm);
		if (tr[rs].mn == tr[x].mn) pushtm(rs, tr[x].tm);
		tr[x].tm = 0;
	}
}

void upd(int l, int r, int p, int x) {
	if (l == r) return tr[x].mn = 0, tr[x].ct = 1, void();
	pushdown(x);
	if (p <= mid) upd(l, mid, p, ls);
	else upd(mid + 1, r, p, rs);
	pushup(x);
}

void add(int l, int r, int s, int t, int c, int x) {
	if (t < s) return;
	if (s <= l && r <= t) return pushtg(x, c);
	pushdown(x);
	if (s <= mid) add(l, mid, s, t, c, ls);
	if (t > mid) add(mid + 1, r, s, t, c, rs);
	pushup(x);
}

void ins(int l, int r, int s, int t, int c, int x) {
	if (t < s) return;
	if (s <= l && r <= t) return pushtm(x, c);
	pushdown(x);
	if (s <= mid) ins(l, mid, s, t, c, ls);
	if (t > mid) ins(mid + 1, r, s, t, c, rs);
	pushup(x);
}

ll qry(int l, int r, int s, int t, int x) {
	if (s <= l && r <= t) return tr[x].sum;
	pushdown(x);
	ll res = 0;
	if (s <= mid) res += qry(l, mid, s, t, ls);
	if (t > mid) res += qry(mid + 1, r, s, t, rs);
	return res;
}

int main() {
	n = rd();
	for (int i = 1, x, y; i <= n; i++) a[i] = rd();
	m = rd();
	for (int i = 1, l, r; i <= m; i++) 
		l = rd(), r = rd(), q[r].pb(mp(l, i));
	for (int i = 1; i <= n; i++) {
		while (tp[0] && a[st[tp[0]][0]] < a[i]) 
			add(1, n, st[tp[0] - 1][0] + 1, st[tp[0]][0], a[i] - a[st[tp[0]][0]], 1), tp[0]--;
		while (tp[1] && a[st[tp[1]][1]] > a[i])
			add(1, n, st[tp[1] - 1][1] + 1, st[tp[1]][1], a[st[tp[1]][1]] - a[i], 1), tp[1]--;
		st[++tp[0]][0] = st[++tp[1]][1] = i;
		add(1, n, 1, i - 1, -1, 1), upd(1, n, i, 1), pushtm(1, 1);
		for (pi p : q[i]) ans[p.se] = qry(1, n, p.fi, i, 1);
	}
	for (int i = 1; i <= m; i++) 
		wr(ans[i]), puts("");
	return 0;
}

标签:CF997E,rs,int,mn,tr,Good,Subsegments,ls,ct
From: https://www.cnblogs.com/Ender32k/p/17569297.html

相关文章

  • 【小学期实训】附加题题解——Good Karma
    [状压dp+容斥原理]实训附加题——GoodKarma目录[状压dp+容斥原理]实训附加题——GoodKarma题目描述题目输入格式输出格式数据范围样例输入1样例输出1样例输入2样例输出2样例解释2Solution题目描述题目链接题目「天空度假山庄」中有一个\(n\)点\(m\)边的无向图,图中点......
  • windows11+gcc安装-good
    MSYS2安装之后,在msys的terminal中执行,可以去安装目录下寻找 >pacman-Smingw-w64-ucrt-x86_64-gcc  GetStartedwithC++andMingw-w64inVisualStudioCode>pacman-S--neededbase-develmingw-w64-x86_64-toolchain选择默认参数(直接回车即可),会执行一系列的......
  • Codeforces 1835F - Good Graph
    goodproblem,badround。判断YES还是NO很trivial,就直接跑最大匹配看看是不是\(n\)即可。如果是NO,那么考虑Hall定理的证明过程构造即可。具体方法就是找到左部任意一非匹配点,在残量网络上BFS可以到达的点,那所有可以到达的左部点形成的集合就是符合要求的反例。因为你......
  • GoodNotes 5(mac手写笔记软件)
    GoodNotes5mac版是一款非常好用的手写笔记软件,GoodNotes5将会支持使用苹果系统的Mac电脑进行手写,并提供多种不同的笔刷来对字体进行书写。GoodNotes5这款软件采用了非常符合Mac用户习惯的界面,其手写风格和功能完全可以满足日常的记录需求。GoodNotes5在书写方面非常流畅,......
  • GoodGraph
    [ABC304E]GoodGraph可以用并查集维护目前已有的连通块。首先应当判断给定的图是不是不好的图,如果是不好的,后面肯定都是不好的。除此之外,可以对于每组点对,记录它们对应的连通块是不可达的。将这些关系排序,然后每次查询时看一看能不能找到这个位置即可。由于时间卡的不是很紧,是有......
  • Good-bye ESNI, hello ECH !(ESNI 与 ECH 的前世今生)
    在当时介绍TLS的最后,提到过虽然TLS能够加密整个通信过程,但是在协商的过程中依旧有很多隐私敏感的参数不得不以明文方式传输,其中最为重要且棘手的就是将要访问的域名,即SNI(ServerNameIndication)。同时还有用于告知客户端可用的应用层协议的ALPN拓展,泄露这个会导致攻击者知......
  • PGP (Pretty Good Privacy) 或 GnuPG (GNU Privacy Guard)
    使用PGP(PrettyGoodPrivacy)或GnuPG(GNUPrivacyGuard)为文件生成密钥验证,通常需要3个步骤:首先创建一对PGP密钥(公钥和私钥),其次为文件生成签名,最后验证文件签名。1.创建PGP密钥对(公钥和私钥):如果您尚未拥有PGP密钥对,请执行以下命令生成一对新密钥:```......
  • How do I ask a good question?
    Iseeagoodweb-word:HowdoIaskagoodquestion?-HelpCenter-StackOverflow ......
  • VS2017使用goodnight theme
    下载源码编译,地址:https://github.com/wuoyrd/vs-theme-goodnight稀里糊涂编译成了pkgdef文件,好在文件正确,又有插件可以读取这种文件1、在扩展中搜索theme,安装此扩展2、安装后打开颜色设置3、导入主题4、选择主题文件5、选择主题为goodnight效果如下:goodnight.pkgd......
  • codeforces 264B B. Good Sequences(dp+数论)
    题目链接:codeforces264B题目大意:给出n个数,利用这n个数构造一个好的序列,好的序列是单调增的,而且序列中相邻的两个元素都不互质,问最长的好序列的长度是多少。题目分析:首先我们定义状态dp[i]表示当前的数进行构造的序列末尾的数的质因数包含i的时候的最长的情况。然后我们从小到大枚......