5/3 树上问题

二进制:

xN+=i=0nai2i   n=O(logx)

倍增:维护从每一个元素开始 2i 个数

应用:元素和,k 级祖先等

uu2ai级祖先,ai=1


1: 树上 k 级祖先

记节点 u2i 级祖先为 f[i,u],那么有 f[i+1,u]=f[i,f[i,u]]。需要注意的是,由于缓存命中问题,i 维开在外面可以提升程序效率。

时间复杂度 O((n+q)logn)

#include <bits/stdc++.h>
using namespace std;
#define rep(ii,aa,bb) for(re ll ii = aa; ii <= bb; ii++)
#define Rep(ii,aa,bb) for(re int ii = aa; ii >= bb; ii--)
typedef long long ll;
typedef unsigned int ull;
typedef double db;
typedef pair<int, int> PII;
const int maxn = 5e5 + 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, q;
ull s;
int f[25][maxn], rt = 1, dep[maxn], hd[maxn], ver[maxn * 2], nxt[maxn * 2], tot;
inline void add(int u, int v) {
ver[++tot] = v; nxt[tot] = hd[u]; hd[u] = tot;
ver[++tot] = u; nxt[tot] = hd[v]; hd[v] = tot;
}
inline void dfs(int u, int fa) {
f[0][u] = fa;
dep[u] = dep[fa] + 1;
for(int i = 0; i < 21; i ++)
f[i + 1][u] = f[i][f[i][u]];
for(int i = hd[u]; i; i = nxt[i]) {
int v = ver[i];
if(v == fa) continue;
dfs(v, u);
}
}
inline int query(int u, int k) {
for(int p = 20; p >= 0; p --)
if(k >= (1 << p))
u = f[p][u],
k -= (1 << p);
return u;
}
inline ull get(ull x) {
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return s = x;
}
int main () {
read(n); read(q); read(s);
rep(i, 1, n) {
int u;
read(u);
if(!u) rt = i;
else add(u, i);
}
// writeln(rt);
dfs(rt, 0);
int ans = 0;
ll Ans = 0;
// rep(i, 1, n) writeln(dep[i]);
rep(i, 1, q) {
// int x, k;
// read(x), read(k);
int x = (get(s) ^ ans) % n + 1;
int k = (get(s) ^ ans) % dep[x];
// write(x), putchar(' '), writeln(k);
ans = query(x, k);
// writeln(ans);
Ans ^= (1ll * ans * i);
}
writeln(Ans);
return 0;
}

2 [JLOI2014]松鼠的新家

维护 tagu 表示 u 到根节点的路径上点权增加量。

对于一次 δ(u,v) 的修改,只需要令 tagu,tagv+1,并且 taglca(u,v),tagfa(lca(u,v))1 即可。

所有修改完成后,进行一次全局 dfs,dfs过程中维护全局量 s,表示当前节点 u 的子树对 u root 的贡献,记

wu=snow=vsubtree(u)tagv

更方便地,我们将 tag[u] 当成前缀和式变量,即每次 dfs 后 tag[u]+=tag[v];


3 生活在树上

δ(u,x),δ(u,y) 总是先经过若干个节点,然后与 δ(x,y) 所形成地链有一个交点 t

dis(u,x)=dis(u,y)dis(x,t)=dis(y,t),因此转化为 δ(x,y) 上寻找一个点 t 满足。

推出 dis(x,y)wt=0,dis(x,y)=wt

对询问差分:查询链上满足点地个数。dis 可以使用树上前缀和,dis(x,y)=dis[x]dis[y]wlca

posted @   Mars_Dingdang  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示