YACS-2023.11-金组

生病了,但是依然强悍。

好久没打 YACS 比赛了。

T1 树的路径

题目大意

https://www.iai.sh.cn/problem/867

给定一棵 n 个结点的树,点的编号为 1n1 号点为根。树上第 i 个点与其父亲的距离为 di。给定一个上限 m,与一个编号为 u 的点,定义 S(u,m)u 的子树中,与 u 距离不超过 m 的点的数量。

对任意点 1in,请计算并输出 S(i,m)

1n2×105,1m1018,1di109.

思路

disi 表示 i 到根节点的路径长度,则 u 子树内节点 vu 的距离不超过 m 等价于 disvdisum,即 disvdisu+m,同时 vsubtree(u)

搞出 dfn 序列,然后在子树内这一限制变成了一段区间,将 dis,dis+m 离散化,变成二维偏序问题,可以离线下来用一个 BIT 搞。

时间复杂度 O(nlogn)

#include <bits/stdc++.h>
using namespace std;
#define rep(ii,aa,bb) for(re int ii = aa; ii <= bb; ii++)
#define Rep(ii,aa,bb) for(re int ii = aa; ii >= bb; ii--)
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair<int, ll> PII;
const int maxn = 2e5 + 5;
namespace IO_ReadWrite {
#define re register
#define gg (p1 == p2 && (p2 = (p1 = _buf) + fread(_buf, 1, 1<<21, stdin), p1 == p2) ? EOF :*p1++)
char _buf[1<<21], *p1 = _buf, *p2 = _buf;
template <typename T>
inline void read(T &x){
x = 0; re T f=1; re char c = gg;
while(c > 57 || c < 48){if(c == '-') f = -1;c = gg;}
while(c >= 48 &&c <= 57){x = (x<<1) + (x<<3) + (c^48);c = gg;}
x *= f;return;
}
inline void ReadChar(char &c){
c = gg;
while(!isalpha(c)) c = gg;
}
template <typename T>
inline void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x/10);
putchar('0' + x % 10);
}
template <typename T>
inline void writeln(T x){write(x); putchar('\n');}
}
using namespace IO_ReadWrite;
int n, tI[maxn], timer, tO[maxn], rev[maxn];
vector <PII> e[maxn];
ll m, dis[maxn], ds[maxn * 2], nD, dpa[maxn];
inline void dfs(int u, int fa) {
dis[u] = dis[fa] + dpa[u];
rev[tI[u] = ++ timer] = u;
for(auto now : e[u]) {
int v = now.first;
if(v == fa) continue;
dfs(v, u);
}
tO[u] = timer;
}
int bit[maxn * 2];
inline int lowbit(int x) {return x & (-x);}
inline void upd(int x, int v) {
for(; x <= nD; x += lowbit(x))
bit[x] += v;
}
inline int psq(int x) {
int res = 0;
for(; x; x -= lowbit(x)) res += bit[x];
return res;
}
struct querys {
int op, id, pos;
int val;
bool operator <(const querys &X)const {
return pos < X.pos;
}
} q[maxn * 2];
int nQ, ans[maxn];
vector <int> qry[maxn];
int main () {
read(n); read(m);
rep(i, 2, n) {
int x;
read(x); read(dpa[i]);
e[x].push_back({i, dpa[i]});
}
dfs(1, 0);
rep(i, 1, n) ds[++ nD] = dis[i], ds[++ nD] = dis[i] + m;
sort(ds + 1, ds + nD + 1);
nD = unique(ds + 1, ds + nD + 1) - (ds + 1);
rep(i, 1, n) {
int val = lower_bound(ds + 1, ds + nD + 1, (dis[i] + m)) - ds;
dis[i] = lower_bound(ds + 1, ds + nD + 1, dis[i]) - ds;
q[++ nQ] = {1, i, tO[i], val};
q[++ nQ] = {-1, i, tI[i] - 1, val};
}
sort(q + 1, q + nQ + 1);
rep(i, 1, nQ) qry[q[i].pos].push_back(i);
rep(i, 1, n) {
upd(dis[rev[i]], 1);
// writeln(dis[rev[i]]);
for(auto id : qry[i]) {
int op = q[id].op, u = q[id].id, val = q[id].val;
// writeln(val);
ans[u] += op * psq(val);
}
}
// rep(i, 1, n) writeln(tI[i]);
rep(i, 1, n) writeln(ans[i]);
return 0;
}

T2 点对乘积

题目大意

https://www.iai.sh.cn/problem/871

给定一棵 n 个点,且以 1 号点为根的有根树,树上编号为 i 的点的父节点为 pi ,权值为 xi 。同时给定一个正整数 m

请你求出有多少对点对 (u,v),满足 uv 的祖先,且 xu×xvm

n105,xi,m109

思路

双倍经验。

枚举 u,然后变成 vsubtree(u),熟悉吗?此时 vu,特判一下即可。

然后就变成 xvmxu。事实上不需要浮点数,有 xvmxu,原因是 xv 是整数,故 xv 是不大于 mxu 的整数,而根据定义,mxu 是不大于 mxu 的最大整数,因此成立。

然后又变成二维偏序了。时间复杂度 O(nlogn)

#include <bits/stdc++.h>
using namespace std;
#define rep(ii,aa,bb) for(re int ii = aa; ii <= bb; ii++)
#define Rep(ii,aa,bb) for(re int ii = aa; ii >= bb; ii--)
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair<int, int> PII;
const int maxn = 1e5 + 5;
namespace IO_ReadWrite {
#define re register
#define gg (p1 == p2 && (p2 = (p1 = _buf) + fread(_buf, 1, 1<<21, stdin), p1 == p2) ? EOF :*p1++)
char _buf[1<<21], *p1 = _buf, *p2 = _buf;
template <typename T>
inline void read(T &x){
x = 0; re T f=1; re char c = gg;
while(c > 57 || c < 48){if(c == '-') f = -1;c = gg;}
while(c >= 48 &&c <= 57){x = (x<<1) + (x<<3) + (c^48);c = gg;}
x *= f;return;
}
inline void ReadChar(char &c){
c = gg;
while(!isalpha(c)) c = gg;
}
template <typename T>
inline void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x/10);
putchar('0' + x % 10);
}
template <typename T>
inline void writeln(T x){write(x); putchar('\n');}
}
using namespace IO_ReadWrite;
int n;
ll x[maxn], xs[maxn * 2], nX, m;
int tI[maxn], tO[maxn], timer, rev[maxn];
vector <int> e[maxn];
inline void dfs(int u) {
rev[tI[u] = ++ timer] = u;
for(auto v : e[u]) dfs(v);
tO[u] = timer;
}
struct querys {
int op, u, pos, val;
} q[maxn * 2];
int nQ;
vector <int> qry[maxn];
ll sum, ans[maxn];
int bit[maxn * 2];
inline int lowbit(int x) {return x & (-x);}
inline void upd(int x, int v) {
for(; x <= nX; x += lowbit(x))
bit[x] += v;
}
inline int psq(int x) {
int res = 0;
for(; x; x -= lowbit(x)) res += bit[x];
return res;
}
int main () {
read(n); read(m);
rep(i, 2, n) {
int u; read(u);
e[u].push_back(i);
}
dfs(1);
rep(i, 1, n) read(x[i]);
rep(i, 1, n) sum -= (1ll * x[i] * x[i] <= m);
rep(i, 1, n) {
xs[++ nX] = x[i];
xs[++ nX] = m / x[i];
}
sort(xs + 1, xs + nX + 1);
nX = unique(xs + 1, xs + nX + 1) - (xs + 1);
rep(i, 1, n) {
int val = lower_bound(xs + 1, xs + nX + 1, (m / x[i])) - xs;
q[++ nQ] = {1, i, tO[i], val};
q[++ nQ] = {-1, i, tI[i] - 1, val};
x[i] = lower_bound(xs + 1, xs + nX + 1, x[i]) - xs;
}
rep(i, 1, nQ) qry[q[i].pos].push_back(i);
rep(i, 1, n) {
upd(x[rev[i]], 1);
for(auto id : qry[i]) {
int op = q[id].op, u = q[id].u, val = q[id].val;
ans[u] += op * 1ll * psq(val);
}
}
rep(i, 1, n) sum += ans[i];
writeln(sum);
return 0;
}

T3 构图

题目大意

https://www.iai.sh.cn/problem/870

小爱想用 n 个点,k 条边来构造一张简单无向联通图(即无重边、无自环),她希望构造出的图能够满足前 m 个点度数恰好为 2

请你帮忙求出满足条件的简单无向联通图的个数,由于答案可能很大,输出答案对 109+7 取模的结果。

n,k50,0m2

思路

最困难的一集。

首先一点,n 个点 k 条边的有标号无向连通图计数是好做的。这篇文章 还给出了一个使用 Stirling 反演进一步优化复杂度的做法。

然后就变成了讨论前 m 个点之间的连接情况。代码没写。

m=0 时,没有限制,答案即为 f(n,k)

m=1 时,一种是剩下 n1 个点用 k2 条边联通,则 1 随便连两个点, (n1)(n2)2f(n1,k2);另一种是剩下 n1 个点分成了两个连通块,枚举其中一个连通块的大小 i 和所用边数 j,每个情况被算了两次,则贡献为

12i=1n2j=0k(n1i)f(i,j)f(n1i,kj)

再考虑 1 和哪两个点连边,从第一个连通块选一个点方案数为 i,第二个连通块选一个点方案数为 n1i,故答案为

(n1)(n2)2f(n1,k2)+12i=1n2j=0k(n1i)f(i,j)f(n1i,kj)×i(n1i)

m=2 时,剩下的点最多可以分为三个连通块,枚举相应情况即可。

posted @   Mars_Dingdang  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示