分类
标签
2-SAT AC自动机 BFS CDQ dfs DP fail树 FFT FFT&NTT FWT hash KD-Tree KMP LCA SPFA STL Tarjan Treap Trie 主席树 乱搞 二分 二分图匹配 二分答案 二维SPFA 交互 位运算 其他 最小生成树 分块 区间DP 半平面交 博弈论 可持久化 可持久化Trie树 后缀数组 图库 平衡树 并查集 插头DP 数学 数论 无旋Treap 日记 暴力 权值树状数组 栈 树DP 树套树 树状数组 树贪心 概率DP 模拟 欧拉定理 点分治 状压DP 生成函数 矩阵乘 线性规划 线段树 组合 网络流 群论 莫比乌斯反演 计算几何 贪心 费用流 高斯消元
772 字
4 分钟
BZOJ 2588 [Spoj 10628] Count on a tree
Description
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
Input
第一行两个整数N,M。 第二行有N个整数,其中第i个整数表示点i的权值。 后面N-1行每行两个整数(x,y),表示点x到点y有一条边。 最后M行每行两个整数(u,v,k),表示一组询问。
Output
M行,表示每个询问的答案。最后一个询问不输出换行符
Sample Input
8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2
Sample Output
2
8
9
105
7
题解
简单来说可以每个节点复制他父亲的节点在新版本中插入自己
然后两个点之间的k小值就是a-lca + b-fa[lca];
#include <cstdio>
#include <queue>
#include <climits>
#include <algorithm>
using namespace std;
struct Seg_Node *null;
struct Seg_Node
{
Seg_Node *ch[2];
int cnt;
//#define cnt(_) ((_) ? (_)->cnt : 0)
Seg_Node(Seg_Node *l, Seg_Node *r)
{
ch[0] = l, ch[1] = r;
cnt = ch[0]->cnt + ch[1]->cnt;
}
Seg_Node(Seg_Node *l, Seg_Node *r, int _cnt)
{
ch[0] = l, ch[1] = r;
cnt = _cnt;
}
Seg_Node *insert(int l, int r, int x)
{
if (l == r)
return new Seg_Node(null, null, cnt + 1);
else
{
int m = l + (r - l) / 2;
if (x <= m)
return new Seg_Node(ch[0]->insert(l, m, x), ch[1]);
else
return new Seg_Node(ch[0], ch[1]->insert(m + 1, r, x));
}
}
};
struct Node
{
vector<Node *> ch;
Node *fa;
int dep, w;
bool vis;
Seg_Node *Seg;
} v[100005];
void addedge(int a, int b)
{
v[a].ch.push_back(&v[b]);
v[b].ch.push_back(&v[a]);
}
void init()
{
null = new Seg_Node(NULL, NULL, 0);
null->ch[0] = null->ch[1] = null;
}
int n, f[100005][20], logn;
void build()
{
v[0].vis = 1;
v[0].Seg = null;
queue<Node *> Q;
Q.push(&v[1]);
v[1].vis = 1;
v[1].dep = 1;
v[1].fa = &v[0];
while (!Q.empty())
{
Node *e = Q.front();
Q.pop();
e->Seg = e->fa->Seg->insert(0, INT_MAX, e->w);
for (Node **p = &e->ch.front(), *u = *p; p <= &e->ch.back(); u = *++p)
{
if (!u->vis)
{
u->vis = 1;
u->dep = e->dep + 1;
u->fa = e;
Q.push(u);
}
}
}
while ((1 << (logn + 1)) <= n)
logn++;
f[1][0] = 1;
for (int i = 2; i <= n; i++)
f[i][0] = v[i].fa - v;
for (int j = 1; j <= logn; j++)
{
for (int i = 1; i <= n; i++)
{
f[i][j] = f[f[i][j - 1]][j - 1];
}
}
}
int lca(int s, int e)
{
if (v[s].dep < v[e].dep)
swap(s, e);
if (v[s].dep > v[e].dep)
{
for (int i = logn; i >= 0; i--)
{
if (v[f[s][i]].dep >= v[e].dep)
s = f[s][i];
}
}
if (s != e)
{
for (int i = logn; i >= 0; i--)
{
if (f[s][i] != f[e][i])
{
s = f[s][i];
e = f[e][i];
}
}
return f[s][0];
}
return s;
}
int Query(int s, int e, int k)
{
int p = lca(s, e);
Seg_Node *Su = v[s].Seg, *Sv = v[e].Seg, *Sp = v[p].Seg, *Sf = v[p].fa->Seg;
int l = 0, r = INT_MAX;
while (l < r)
{
int m = l + (r - l) / 2;
int S = Su->ch[0]->cnt + Sv->ch[0]->cnt - Sp->ch[0]->cnt - Sf->ch[0]->cnt;
if (k > S)
{
k -= S;
l = m + 1;
Su = Su->ch[1];
Sv = Sv->ch[1];
Sp = Sp->ch[1];
Sf = Sf->ch[1];
}
else
{
r = m;
Su = Su->ch[0];
Sv = Sv->ch[0];
Sp = Sp->ch[0];
Sf = Sf->ch[0];
}
}
return l;
}
int main()
{
int m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &v[i].w);
for (int i = 1; i <= n - 1; i++)
{
int s, e;
scanf("%d%d", &s, &e);
addedge(s, e);
}
init();
build();
int ans = 0;
while (m--)
{
int s, e, k;
scanf("%d%d%d", &s, &e, &k);
s ^= ans;
printf(m ? "%d\n" : "%d", ans = Query(s, e, k));
}
}
BZOJ 2588 [Spoj 10628] Count on a tree
https://www.nekomio.com/posts/56/