首页 > 其他分享 >[Ynoi2008] rdCcot 做题记录

[Ynoi2008] rdCcot 做题记录

时间:2024-12-13 20:43:06浏览次数:3  
标签:Ynoi2008 const 记录 ll rdCcot maxn return define mod

link

考虑对于每个连通块,我们寻找一个代表元计数。

可以设定为深度最小的点,若深度同样小,则选定编号更小的。我们对于每个点 \(u\) 求出 \(l_u, r_u\) 表示根据上述比较规则下比 \(u\) 小,且距离不超过 \(C\),最接近 \(u\) 的一左一右两个点。如果 \(l_u, r_u\) 任意一个点存在当前询问区间中则 \(u\) 不是代表元,所以统计 \(l_u < l \le u \le r < r_u\) 的 \(u\) 个数即可。

正确性只需证明非代表元的 \(l_u, r_u\) 一定有一个在 \([l, r]\) 中,反证,\(u\) 只和在上述比较规则小比他大的点 C - 连通,那么这些点一定也达到不了其他点,这与 \(u\) 是非代表元矛盾。

考虑点分治,按距离依次加入所有点,用线段树二分求出与某个位置最近的一左一右两个位置。最后做一个二维数点即可。

  • 启示:设定代表元
点击查看代码
#include <bits/stdc++.h>

namespace Initial {
	#define ll int
	#define ull unsigned long long
	#define fi first
	#define se second
	#define mkp make_pair
	#define pir pair <ll, ll>
	#define pb emplace_back
	#define i128 __int128
	using namespace std;
	const ll maxn = 6e5 + 10, inf = 1e9, mod = 1e9 + 7;
	ll power(ll a, ll b = mod - 2) {
		ll s = 1;
		while(b) {
			if(b & 1) s = 1ll * s * a %mod;
			a = 1ll * a * a %mod, b >>= 1;
		} return s;
	}
	template <class T>
	const ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }
	template <class T>
	void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }
	template <class T>
	void chkmax(T &x, const T y) { x = x < y? y : x; }
	template <class T>
	void chkmin(T &x, const T y) { x = x > y? y : x; }
} using namespace Initial;

namespace IO {
	char buf[1 << 22], *p1 = buf, *p2 = buf;
//	#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)
	template <class T>
	void rd(T &x) {
		char ch; bool f = 0;
		while(!isdigit(ch = getchar()));
			if(ch == '-') f = 1;
		x = ch - '0';
		while(isdigit(ch = getchar()))
			x = (x << 1) + (x << 3) + ch - '0';
		if(f) x = -x;
	} char obuf[1 << 22], *O = obuf;
	void putc(const char ch) { *O++ = ch; }
	void write(ll x) {
		if(x < 0) *O++ = '-', x = -x;
		if(x > 9) write(x / 10);
		*O++ = x % 10 + '0';
	}
	void write(const ll x, const char ch) { write(x), putc(ch); }
	void flush() { fwrite(buf, O - buf, 1, stdout); }
} using IO::rd; using IO::write; 

ll n, m, C, l[maxn], r[maxn], dep[maxn], id[maxn], w[maxn];
vector <ll> to[maxn];
void getdep(ll u, ll fa = 0) {
	dep[u] = dep[fa] + 1;
	for(ll v: to[u])
		if(v ^ fa) getdep(v, u);
}

namespace centroid_divide {
	struct SGT {
		ll mn[maxn << 2];
		const void modify(const ll p, const ll l, const ll r, const ll x) {
			mn[p] = min(mn[p], w[x]); if(l == r) return;
			const ll mid = l + r >> 1;
			if(x <= mid) modify(p << 1, l, mid, x);
			else modify(p << 1|1, mid + 1, r, x);
		}
		const ll queryl(const ll p, const ll l, const ll r, const ll x) {
			if(l > x || mn[p] >= w[x]) return 0;
			if(l == r) return l; const ll mid = l + r >> 1;
			const ll c = queryl(p << 1|1, mid + 1, r, x);
			if(c) return c;
			return queryl(p << 1, l, mid, x);
		}
		const ll queryr(const ll p, const ll l, const ll r, const ll x) {
			if(r < x || mn[p] >= w[x]) return n + 1;
			if(l == r) return l; ll mid = l + r >> 1;
			ll c = queryr(p << 1, l, mid, x);
			if(c <= n) return c;
			return queryr(p << 1|1, mid + 1, r, x);
		}
		const void clr(const ll p, const ll l, const ll r) {
			if(mn[p] >= inf) return; mn[p] = inf;
			if(l == r) return; ll mid = l + r >> 1;
			clr(p << 1, l, mid), clr(p << 1|1, mid + 1, r);
		}
	} tr;
	ll bs, rt, siz[maxn]; bool vis[maxn];
	void findrt(ll u, ll N, ll fa = 0) {
		siz[u] = 1; ll mx = 0;
		for(ll v: to[u])
			if(v != fa && !vis[v]) {
				findrt(v, N, u), siz[u] += siz[v];
				mx = max(mx, siz[v]);
			} mx = max(mx, N - siz[u]);
		if(mx < bs) bs = mx, rt = u;
	} ll dis[maxn], len; pir vertice[maxn];
	void dfs(ll u, ll fa = 0) {
		siz[u] = 1, vertice[++len] = mkp(dis[u], u);
		for(ll v: to[u])
			if(v != fa && !vis[v]) {
				dis[v] = dis[u] + 1, dfs(v, u);
				siz[u] += siz[v];
			}
	}
	void solve(ll u, ll N) {
		bs = inf, findrt(u, N); len = 0;
		vis[u = rt] = true, dis[u] = 0, dfs(u);
		sort(vertice + 1, vertice + 1 + len), tr.clr(1, 1, n);
		for(ll i = len, j = 1; i; i--) {
			ll x = vertice[i].se, y;
			while(j <= len && dis[y = vertice[j].se] + dis[x] <= C)
			 	tr.modify(1, 1, n, y), ++j;
			chkmax(l[x], tr.queryl(1, 1, n, x));
			chkmin(r[x], tr.queryr(1, 1, n, x));
		}
		for(ll v: to[u])
			if(!vis[v]) solve(v, siz[v]);
	}
}

struct _BIT {
	ll dat[maxn];
	void add(ll x, ll v) {
		for(; x <= n; x += x & -x) dat[x] += v;
	}
	ll ask(ll x) {
		ll v = 0;
		for(; x; x -= x & -x) v += dat[x];
		return v;
	}
} BIT; ll ans[maxn]; pir ff[maxn];
struct qur { ll l, r, id; } q[maxn];

int main() {
	rd(n), rd(m), rd(C);
	for(ll i = 2, x; i <= n; i++)
		rd(x), to[x].pb(id[i] = i), to[i].pb(x); getdep(1);
	sort(id + 1, id + 1 + n, [](ll x, ll y) {
		return dep[x] ^ dep[y]? dep[x] < dep[y] : x < y;
	});
	for(ll i = 1; i <= n; i++) w[id[i]] = i;
	for(ll i = 1; i <= n; i++) r[i] = n + 1;
	centroid_divide::solve(1, n);
	for(ll i = 1; i <= n; i++) ff[i] = mkp(r[i], l[i]);
	sort(ff + 1, ff + 1 + n);
	for(ll i = 1, l, r; i <= m; i++)
		rd(q[i].l), rd(q[i].r), q[i].id = i;
	sort(q + 1, q + 1 + m, [](const qur a, const qur b) {
		return a.r < b.r;
	});
	for(ll i = 1, j = 0, k = 0; i <= n; i++) {
		BIT.add(l[i] + 1, 1);
		while(j < n && ff[j + 1].fi == i) BIT.add(ff[++j].se + 1, -1);
		while(k < m && q[k + 1].r == i) ++k, ans[q[k].id] = BIT.ask(q[k].l);
	} BIT = {};
	sort(q + 1, q + 1 + m, [](const qur a, const qur b) {
		return a.l < b.l;
	});
	for(ll i = 1, j = 0; i <= n; i++) {
		while(j < m && q[j + 1].l == i)
			++j, ans[q[j].id] -= BIT.ask(n - q[j].r + 1);
		BIT.add(n - r[i] + 2, 1);
	}
	for(ll i = 1; i <= m; i++) printf("%d\n", ans[i]);
	return 0;
}

标签:Ynoi2008,const,记录,ll,rdCcot,maxn,return,define,mod
From: https://www.cnblogs.com/Sktn0089/p/18605805

相关文章

  • [Ynoi2011] 成都七中 做题记录
    Educational。link连通块问题不强于路径统计问题,考虑点分治,对于每个分治点统计所有包含该点的连通块。判断一个连通块是否包含一个分治点是容易的,DFS一遍判断路径上最大最小值是否超出限制。DFS可以求出所有点到分治点的路径上的最大最小值,视作一个区间\([mn_i,mx_i]\),颜色......
  • [Ynoi2013] D2T2 做题记录
    link很厉害的题目。先弱化题目,考虑\(l=1,r=n\)怎么做。设\(f(x,y)\)表示只保留值域在\([a_x,a_y]\)的数的最大子段和,有用状态数为\(\mathcalO(n^2)\)。我们发现这玩意其实是可以分治的:将原序列分成两半,求出左半部分和右半部分的只保留\([a_x,a_y]\)中的数的......
  • [Ynoi2010] Brodal queue 做题记录
    link加深了对分块算法的理解。题目相当于求解一个区间内每种颜色出现次数平方和,这种题显然无法polylog。先尝试分块,将贡献拆成散块-散块;散块-整块;整块-整块三种。散块-散块是容易的,直接用桶计数就好。整块-整块:设\(d_{c,i}\)表示颜色\(c\)在前\(i\)个块......
  • [Ynoi2000] tmostnrq 做题记录
    link先离线扫描线,相当于在\(l\)这个时刻加入一个点,然后每次令所有点向某个点的方向移动一步,在\(r\)时刻查询某个点的位置。以\(1\)为根,对于\(a_i\)相当于令\(1\toa_i\)这条链上所有点向下移动一步,其他点向上移动一步。我们需要同时支持这两种操作,但是不能每个点暴力......
  • 记录_信号完整性上机报告
    《信号完整性》实验报告实验工程图:2.1阻抗突变处的反射:一、实验目的本实验旨在研究信号在遇到传输线阻抗突变时产生的反射现象。通过设置不同阻抗的传输线,模拟和分析信号反射系数的变化,观察反射对信号波形的影响。实验的核心目标是理解阻抗突变如何影响信号传播,计算反射系数,......
  • 工作CASE_1 Hold Lot 已经Release但是Hold记录为空
    说明:DWT_HOLD_LOT的HoldLotHoldEvent('Hold','EditHoldComment','Release'),且每个Event都为一条记录,每条记录都有对应的RELEASE_EVENT_TIME,HOLD_SYS_ID,HOLD_RELEASEHOLDLOT已经Release,但是对应HOLD记录的Release时间是空的SELECT*FROMDWT_HOLD_LOTdhlW......
  • Linux 常用命令 日常工作记录 学习记录
     命令解释示例cd/opt/**/** 跳转目录 cd- 回到上一次目录 ping**.com 测试网络pingbaidu.comcal查看日历calssh 10.64.**.**跳转到其他服务器ssh10.64.1.1tail-ftest.log查看日志文件,并持续输出 ps-ef|grepjava查看......
  • 微信聊天记录中过期文件的找回方法
    在使用微信的过程中,我们经常会收到各种文件,如图片、视频、文档等。然而,有时由于种种原因,这些文件可能会过期,导致我们无法直接打开或下载。那么,当微信聊天记录中的文件过期时,我们还能通过哪些方法找回它们呢?本文将为您详细介绍几种实用的找回过期微信文件的方法。一、利用微信......
  • 记录一个困扰两天的问题:git 换行符LF与CRLF转换问题
    此篇文章在2023年11月27日被记录1、背景这两天在维护公司一个老旧项目,编译是用bat批处理+python实现的,但是把最新的代码拉下来后发现编译不过去,提示bat指令有错误,并且是很离谱的错误,但是回退到之间的稳定版本,命令行编译是没有任何问题的,经过两天N多次试错失败后终于发现了一些......
  • QT日志类SimpleQtLogger的简单记录
    在现代软件开发中,日志记录是必不可少的部分。它不仅帮助开发者在调试和维护软件时了解程序的运行状态,还能提供关键的错误信息。对于使用Qt框架开发应用程序的开发者来说,选择一个合适的日志库至关重要。本文将详细介绍Qt日志库SimpleQtLogger的特点、安装方法、使用示例以及它在实......