- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
又是一道考场想到做法写不出来的题 对于 \(\ge x\) 的数全部 \(+1\) 的操作有个很优美的大材小用的想法,那就是分段函数 于是线段树倒着维护分段函数,为了快速统计,要记录线段树结点中每个点跳出本结点的值, vector 记下排序 于是区间可以拆成 \(\log\) 段,每段二分 \(\log\) 统计,注意到从后往前,拆开后分段函数不能合并,不然复杂度会错,但可以找到最大的值使得它扔进函数出来后 \(\le k\) ,这需要在分段函数上二分更新,每个拆开后的区间更新一次 那么在树上就硬套个树剖, \(O(n \log n+q\log^3n)\) ,恶心的是树上路径要维护向上和下的分段函数,记录的信息也要对应多维护,比较繁琐 但是 \(log^3\) 过掉 \(2\times 10^5\) 也是厉害的 。
正解当然得正确点 \(O(n\log n+q\log^2n)\) 考虑这个困难的操作,仍然是可以更巧妙地弄出最后有哪些数的 倒着加数 \(x\) ,每次新加的数受之前加的数影响,可以发现新加的数就是当前自然数集合从小到大没有加入过的第 \(x\) 个 那这样就可以简单的线段树上二分得到了 然后硬上树剖,考虑拆段后询问应该怎么处理 只有一个段时直接查询 \(\le k\) 的数有多少,记为 \(p\) ,那么下一个段就要查询 \(\le k-p\) 的数有多少了 仍然是要维护向上和向下信息的 。
代码当然是写了恶心的做法,毕竟考场上写了 \(4Kb\) 怎么可以弃掉 。
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#define eb emplace_back
using namespace std;
template <typename Tp>
void read(Tp &x) {
x = 0; char ch = getchar(); int f = 0;
for(; !isdigit(ch); f = (ch == '-' ? 1 : f), ch = getchar());
for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar());
if (f) x = ~x + 1;
}
const int N = 2e5 + 5, inf = 4e5;
int n, m, a[N];
vector<int> G[N];
int fa[N], dfn[N], sz[N], dfc, top[N], dep[N], son[N], ed[N], rev[N];
void dfs1(int x) {
sz[x] = 1, dep[x] = dep[fa[x]] + 1;
for(auto v : G[x]) {
if (v == fa[x]) continue;
fa[v] = x, dfs1(v), sz[x] += sz[v], son[x] = (sz[son[x]] < sz[v] ? v : son[x]);
}
}
void dfs2(int x, int t) {
top[x] = t, ed[t] = x, dfn[x] = ++dfc, rev[dfc] = x;
if (son[x]) dfs2(son[x], t);
for(auto v : G[x]) {
if (v == fa[x] || v == son[x]) continue;
dfs2(v, v);
}
}
struct node{int a, b;};
typedef vector<node> Vec;
vector<node> seg[2][N * 19];
vector<int> vec[2][N * 19];
int ls[N * 19], rs[N * 19], size, R[N], rt[N];
int MaxDefine(Vec &seg, int z){return (z == seg.size() - 1) ? inf : seg[z + 1].a - 1;}
void Merge(Vec &c, Vec &a, Vec &b) {
for(int i = 0, j = 0; i < a.size(); i++) {
while (MaxDefine(b, j) < a[i].a + a[i].b) ++j;
int now = a[i].a;
while (j < b.size()) {
c.eb(node{now, a[i].b + b[j].b});
if (MaxDefine(b, j) >= MaxDefine(a, i) + a[i].b) break;
now = MaxDefine(b, j) + 1 - a[i].b, ++j;
}
}
}
void Merge(vector<int> &a, vector<int> &b) {
int i = 0, j = 0, k = 0; vector<int> c(a.size() + b.size());
while (i < a.size() && j < b.size())
if (a[i] < b[j]) c[k++] = a[i++]; else c[k++] = b[j++];
while (i < a.size()) c[k++] = a[i++];
while (j < b.size()) c[k++] = b[j++];
swap(a, c);
}
void merge(vector<int> &a, vector<int> &b, Vec &c) {
vector<int> d(b.size());
for(int i = 0, j = 0; i < b.size(); i++) {
while (MaxDefine(c, j) < b[i]) ++j; d[i] = b[i] + c[j].b;
}
Merge(a, d);
}
void build(int t, int &p, int l, int r) {
if (!p) p = ++size;
if (l == r) {
int now = a[rev[l + dfn[t] - 1]];
for(int j = 0; j < 2; j++)
seg[j][p].eb(node{0, 0}), seg[j][p].eb(node{now, 1}), vec[j][p].eb(now);
return;
}
int mid = l + r >> 1;
build(t, ls[p], l, mid), build(t, rs[p], mid + 1, r);
Merge(seg[0][p], seg[0][rs[p]], seg[0][ls[p]]), Merge(seg[1][p], seg[1][ls[p]], seg[1][rs[p]]);
merge(vec[0][p] = vec[0][ls[p]], vec[0][rs[p]], seg[0][ls[p]]);
merge(vec[1][p] = vec[1][rs[p]], vec[1][ls[p]], seg[1][rs[p]]);
}
void build(int t){R[t] = dfn[ed[t]] - dfn[t] + 1, build(t, rt[t], 1, R[t]);}
void calc(Vec &seg, int &x) {
int l = 0, r = seg.size() - 1, mid = l + r >> 1, z;
for(; l <= r; mid = l + r >> 1)
if (MaxDefine(seg, mid) >= x) z = mid, r = mid - 1; else l = mid + 1;
x += seg[z].b;
}
int count(vector<int> &vec, int k) {
int l = 0, r = vec.size() - 1, mid = l + r >> 1, z = -1;
for(; l <= r; mid = l + r >> 1)
if (vec[mid] <= k) z = mid, l = mid + 1; else r = mid - 1;
return z + 1;
}
void update(int &Mx, Vec &seg) {
int l = 0, r = seg.size() - 1, mid = l + r >> 1, z = 0;
for(; l <= r; mid = l + r >> 1)
if (seg[mid].a + seg[mid].b <= Mx) z = mid, l = mid + 1; else r = mid - 1;
if (MaxDefine(seg, z) + seg[z].b <= Mx) Mx = MaxDefine(seg, z);
else Mx -= seg[z].b;
}
int Query(int p, int fl, int l, int r, int x, int y, int &Mx) {
if (!p || x > r || y < l || x > y) return 0;
if (x <= l && r <= y){
int res = count(vec[fl][p], Mx); update(Mx, seg[fl][p]);
return res;
}
int mid = l + r >> 1, res = 0;
if (!fl) {
if (x <= mid) res = Query(ls[p], fl, l, mid, x, y, Mx);
if (y > mid) res += Query(rs[p], fl, mid + 1, r, x, y, Mx);
}
else {
if (y > mid) res = Query(rs[p], fl, mid + 1, r, x, y, Mx);
if (x <= mid) res += Query(ls[p], fl, l, mid, x, y, Mx);
}
return res;
}
int LCA(int x, int y) {
while (top[x] ^ top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
return (dep[x] < dep[y] ? x : y);
}
int solve(int u, int v, int k) {
int w = LCA(u, v), res = 0, Mx = k;
while (top[v] != top[w])
res += Query(rt[top[v]], 1, 1, R[top[v]], 1, dfn[v] - dfn[top[v]] + 1, Mx), v = fa[top[v]];
res += Query(rt[top[w]], 1, 1, R[top[w]], dfn[w] - dfn[top[w]] + 1, dfn[v] - dfn[top[w]] + 1, Mx);
vector<int> d;
while (top[u] != top[w]) d.eb(u), u = fa[top[u]];
if (dep[u] > dep[w])
res += Query(rt[top[w]], 0, 1, R[top[w]], dfn[w] - dfn[top[w]] + 2, dfn[u] - dfn[top[w]] + 1, Mx);
for(int i = (int)d.size() - 1; ~i; i--)
res += Query(rt[top[d[i]]], 0, 1, R[top[d[i]]], 1, dfn[d[i]] - dfn[top[d[i]]] + 1, Mx);
return res;
}
int main() {
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
int t; read(n), read(m), read(t);
for(int i = 1; i <= n; i++) read(a[i]);
for(int i = 1, u, v; i < n; i++) read(u), read(v), G[u].eb(v), G[v].eb(u);
dfs1(1), dfs2(1, 1);
for(int i = 1; i <= n; i++) if (top[i] == i) build(i);
for(int i = 1, u, v, k, lst = 0; i <= m; i++)
read(u), read(v), read(k), u ^= (lst * t), v ^= (lst * t), k ^= (lst * t), printf("%d\n", lst = solve(u, v, k));
}
最后此篇关于D7lsu.树题的文章就讲到这里了,如果你想了解更多关于D7lsu.树题的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
关闭。这个问题需要debugging details .它目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and th
我试图用这种形式简单地获取数字 28 integer+space+integer+integer+space+integer我试过这个正则表达式 \\s\\d\\d\\s 但我得到了两个数字11 和
最近一直在学习D语言。我一直对运行时感到困惑。 从我能收集到的关于它的信息中,(这不是很多)我知道它是一种有助于 D 的一些特性的运行时。像垃圾收集一样,它与您自己的程序一起运行。但是既然 D 是编译
想问一下这两个正则表达式有区别吗? \d\d\d 与 \d{3} 我已经在我的本地机器上使用 Java 和 Windows 操作系统对此进行了测试,两者都工作正常并且结果相同。但是,当在 linux
我正在学习 Go,而且我坚持使用 Go 之旅(exercise-stringer.go:https://tour.golang.org/methods/7)。 这是一些代码: type IPAddr
我在Java正则表达式中发现了一段令我困惑的代码: Pattern.compile( "J.*\\d[0-35-9]-\\d\\d-\\d\\d" ); 要编译的字符串是: String string
我在 ruby 代码上偶然发现了这个。我知道\d{4})\/(\d\d)\/(\d\d)\/(.*)/是什么意思,但是\1-\2-\3-\4 是什么意思? 最佳答案 \1-\2-\3-\4 是 b
我一直在努力解决这个问题,这让我很恼火。我了解 D 运行时库。它是什么,它做什么。我也明白你可以在没有它的情况下编译 D 应用程序。就像 XoMB 所做的那样。好吧,XoMB 定义了自己的运行时,但是
我有两个列表列表,子列表代表路径。我想找到所有路径。 List> pathList1 List> pathList2 当然是天真的解决方案: List> result = new ArrayList>
我需要使用 Regex 格式化一个字符串,该字符串包含数字、字母 a-z 和 A-Z,同时还包含破折号和空格。 从用户输入我有02-219 8 53 24 输出应该是022 198 53 24 我正在
目标是达到与this C++ example相同的效果: 避免创建临时文件。我曾尝试将 C++ 示例翻译为 D,但没有成功。我也尝试过不同的方法。 import std.datetime : benc
tl;dr:你好吗perfect forwarding在 D? 该链接有一个很好的解释,但例如,假设我有这个方法: void foo(T)(in int a, out int b, ref int c
有什么方法可以在 D 中使用abstract auto 函数吗? 如果我声明一个类如下: class MyClass { abstract auto foo(); } 我收到以下错误: mai
有没有人为内存中重叠的数组切片实现交集?算法在没有重叠时返回 []。 当 pretty-print (使用重叠缩进)内存中重叠的数组切片时,我想要这个。 最佳答案 如果您确定它们是数组,那么只需取 p
我已经开始学习 D,但我在使用 Andrei Alexandrescu 所著的 The D Programming Language 一书中提供的示例时遇到了一些麻烦。由于 int 和 ulong 类
如何创建一个不可变的类? 我的目标是创建一个实例始终不可变的类。现在我只是用不可变的方法和构造函数创建了一个“可变”类。我将其称为 mData,m 表示可变。然后我创建一个别名 alias immut
不久前我买了《The D Programming Language》。好书,很有教育意义。但是,我在尝试编译书中列出的语言功能时遇到了麻烦:扩展函数。 在这本书中,Andrei 写了任何可以像这样调用
我在 D http://www.digitalmars.com/d/2.0/lazy-evaluation.html 中找到了函数参数的惰性求值示例 我想知道如何在 D 中实现可能的无限数据结构,就像
这个问题在这里已经有了答案: 12 年前关闭。 Possible Duplicate: Could anyone explain these undefined behaviors (i = i++
当前是否可以跨模块扫描/查询/迭代具有某些属性的所有函数(或类)? 例如: source/packageA/something.d: @sillyWalk(10) void doSomething()
我是一名优秀的程序员,十分优秀!