D7lsu. 树题
\(\text{Solution}\)
又是一道考场想到做法写不出来的题
对于 \(\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\) 怎么可以弃掉
\(\text{Code}\)
#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. 树题的更多相关文章
- jzoj5988. 【WC2019模拟2019.1.4】珂学计树题 (burnside引理)
		传送门 题面 liu_runda曾经是个喜欢切数数题的OIer,往往看到数数题他就开始刚数数题.于是liu_runda出了一个数树题.听说OI圈子珂学盛行,他就在题目名字里加了珂学二字.一开始liu_ ... 
- JZOJ5988 珂学计树题
		题意 liu_runda曾经是个喜欢切数数题的OIer,往往看到数数题他就开始刚数数题.于是liu_runda出了一个数树题.听说OI圈子珂学盛行,他就在题目名字里加了珂学二字.一开始liu_rund ... 
- ●线段树题之wows
		●模拟考试的一道似乎是学长出的题,还不错,挺考代码能力的.以此记录. ●题目以被上传(改了改说法),6128 Lence的方块们 ● (像手纸一样长的贴图……) ●题目大意: 有横向排布的n个点,每个 ... 
- JZOJ 5988 珂学计树题 (Burnside引理)
		什么神题a-没学过Burnside引理a学了也做不来系列-考场没怎么看这题,上最后十分钟打了样例就溜了-然后这题爆0了. Here CODE #include <cctype> #incl ... 
- 一道Postgresql递归树题
		转载请注明出处: https://www.cnblogs.com/funnyzpc/p/13698249.html 也是偶然的一次,群友出了一道题考考大家,当时正值疫情最最严重的三月(借口...),披 ... 
- hdu 3397 Sequence operation(很有意思的线段树题)
		Sequence operation Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ... 
- 线段树题集 (cf版)
		lazy区间修改 : http://acm.hdu.edu.cn/showproblem.php?pid=4902 (hdu4902) http://acm.hdu.edu.cn/showpr ... 
- BZOJ4408: [Fjoi 2016]神秘数【主席树好题】
		Description 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13}, 1 = 1 2 = 1+1 3 = 1+1+1 4 = 4 5 = ... 
- BZOJ1067&P2471 [SCOI2007]降雨量[线段树裸题+细节注意]
		dlntqlwsl 很裸的一道线段树题,被硬生生刷成了紫题..可能因为细节问题吧,我也栽了一次WA50分.不过这个隐藏条件真的对本菜鸡来说不易发现啊. 未知的年份连续的就看成一个就好了,把年份都离散化 ... 
- Mango DS Traning #49 ---线段树3  解题手记
		Training address: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=38994#overview B.Xenia and B ... 
随机推荐
- 几个Shell脚本的例子
			[例子:001]判断输入为数字,字符或其他 #!/bin/bash read -p "Enter a number or string here:" input case $inp ... 
- (linux笔记)开放防火墙端口
			关闭防火墙 CentOS 7.RedHat 7 之前的 Linux 发行版防火墙开启和关闭( iptables ): 即时生效,重启失效 #开启 service iptables start #关闭 ... 
- 点击div实现选中效果
			先上一份效果图.原来的checked多选框还是存在的,我只不过隐藏了,让他的整个div的范围都是可以点击的,右上角三个点是可以删除当前元素,左下角的播放按钮可以点击播放语音,主要是利用z-index把 ... 
- 【python】读取nc文件
			读取nc文件前的准备,安装一些库 1.先把几个用到的库下载 Cartopy 简介与安装(转载) - 简书 (jianshu.com) Python Extension Packages for Win ... 
- mysql重新设置列的自增初始值
			alter table xxx auto_increment = 100; 因为设置了列的自增之后,若删除过一些行,下次再新增时还会从已删除的id算起自增,为了让数据看起来连续,可以重新设置自增起始值 ... 
- flask中request请求中各种传参
			from flask import Flask, request from werkzeug.datastructures import FileStorage app = Flask(__name_ ... 
- linux清除日志和文件缓存
			1.查找大文件,从根目录 find / -type f -size +800M 2.查看磁盘挂载情况及挂载目录 df -lh 3.查看内存使用情况 free -m 4.清除缓存 echo 3 > ... 
- Ext中数据表格序号超过3位数时显示省略号
			问题 在老项目上优化时,遇到了Ext中ColumnModel序号超过3位数时,自动显示了省略号,不友好 修改方法 给RowNumberer添加样式 new Ext.grid.RowNumberer({ ... 
- nodejs 配置国内镜像
			npm config set registry https://registry.npm.taobao.org npm config set disturl https://npm.taobao.or ... 
- HDFS相关问题处理
			机房搬迁后datanode启动失败,报错如下: 2022-10-21 10:28:40,551 INFO org.apache.hadoop.hdfs.server.common.Storage: L ... 
