P3920 [WC2014]紫荆花之恋
要求维护一颗带边权和点权 的树,支持动态插入叶子 以及 询问树上有多少点对满足两个点的点权之和大于两点间的边权之和,即 。
强制在线。
点数 , 边权 , 点权 。
std
先不考虑动态插入叶子,即给你一棵树,求出答案。
按照套路,对于这种大规模树上路径问题,考虑点分治。
考虑询问,由于点分治只统计经过根节点的方案数,那么设当前分治中心为 ,一条经过 的路径 可分为 和 两段,那么 。
考虑到原式可移项为 ,我们可以用一个数据结构,支持插入和求排名操作维护节点 的所有 ,查询 的排名即可。
对于多次点分治,可用点分树优化。
再考虑动态插入叶子怎么做。
显然,定期重构部分点分树即可。
总时间复杂度为 。
#include <bits/stdc++.h>
using namespace std;
namespace Fread
{
const int SIZE = 1 << 23;
char buf[SIZE], *S, *T;
inline char getchar()
{
if (S == T)
{
T = (S = buf) + fread(buf, 1, SIZE, stdin);
if (S == T)
return '\n';
}
return *S++;
}
}
namespace Fwrite
{
const int SIZE = 1 << 23;
char buf[SIZE], *S = buf, *T = buf + SIZE;
inline void flush()
{
fwrite(buf, 1, S - buf, stdout);
S = buf;
}
inline void putchar(char c)
{
*S++ = c;
if (S == T)
flush();
}
struct NTR
{
~NTR()
{
flush();
}
} ztr;
}
#ifdef ONLINE_JUDGE
#define getchar Fread::getchar
#define putchar Fwrite::putchar
#endif
#define ll long long
inline ll read()
{
ll x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = x * 10 + c - '0', c = getchar();
return x * f;
}
inline void write(ll x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
const int _ = 1e5 + 10, S = 350, inf = 1e7 + 10;
const double alpha = 0.95;
int n, r[_];
int sz[_];
bool vis[_];
int tot, head[_], to[_ << 1], nxt[_ << 1];
ll lst;
inline void add(int u, int v)
{
to[++tot] = v;
nxt[tot] = head[u];
head[u] = tot;
}
inline pair<int, int> get_rt(int rt, int f, int pre)
{
sz[rt] = 1;
int mx = 0;
pair<int, int> ans = {inf, 0};
for (int i = head[rt]; i; i = nxt[i])
{
int v = to[i];
if (vis[v] || v == f)
continue;
ans = min(ans, get_rt(v, rt, pre));
sz[rt] += sz[v];
mx = max(mx, sz[v]);
}
ans = min(ans, {max(mx, pre - sz[rt]), rt});
return ans;
}
struct DIS
{
int f[_][17], dep[_], dis[_];
inline void insert(int x, int fa, int c)
{
f[x][0] = fa;
dep[x] = dep[fa] + 1;
dis[x] = dis[fa] + c;
for (int i = 1; i <= 16; ++i)
f[x][i] = f[f[x][i - 1]][i - 1];
}
inline int LCA(int x, int y)
{
if (dep[x] < dep[y])
swap(x, y);
for (int i = 16; ~i; --i)
if (dep[f[x][i]] >= dep[y])
x = f[x][i];
if (x == y)
return x;
for (int i = 16; ~i; --i)
if (f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
return f[x][0];
}
inline int Dis(int x, int y)
{
return dis[x] + dis[y] - 2 * dis[LCA(x, y)];
}
} bz;
struct ABC
{
vector<int> a, b;
inline void insert(int x)
{
b.insert(lower_bound(b.begin(), b.end(), x), x);
if (b.size() >= S)
{
vector<int> c, d;
int i = 0, j = 0;
for (; i < a.size() && j < b.size();)
if (a[i] < b[j])
c.push_back(a[i++]);
else
c.push_back(b[j++]);
while (i < a.size())
c.push_back(a[i++]);
while (j < b.size())
c.push_back(b[j++]);
swap(a, c);
swap(b, d);
}
}
inline int rank(int x)
{
return (upper_bound(a.begin(), a.end(), x) - a.begin()) + (upper_bound(b.begin(), b.end(), x) - b.begin()) - 2;
}
inline void clear()
{
a.clear();
b.clear();
}
} pa[_ << 1], pb[_ << 1];
struct D_F_Z
{
int f[_], dep[_], siz[_];
inline int query(int x, int r)
{
int ans = 0;
for (int i = x, j; f[i]; i = j)
{
j = f[i];
int dis = r - bz.Dis(x, j);
ans += pa[j].rank(dis) - pb[i].rank(dis);
}
return ans;
}
inline void insert(int x, int v, int Rt)
{
pa[x].insert(-v);
for (int i = x, j; i != Rt; i = j)
{
j = f[i];
int dis = bz.Dis(x, j) - v;
if (j != Rt)
pa[j].insert(dis);
pb[i].insert(dis);
}
}
inline void clear(int x, int fa, int deps)
{
vis[x] = 0;
for (int i = head[x]; i; i = nxt[i])
{
int v = to[i];
if (v == fa || dep[v] <= deps)
continue;
clear(v, x, deps);
}
}
inline int build(int x, int pre, int fa, int Rt)
{
int rt = get_rt(x, 0, pre).second, bas = sz[x];
pa[rt].clear();
pb[rt].clear();
f[rt] = fa;
siz[rt] = vis[rt] = 1;
dep[rt] = dep[fa] + 1;
insert(rt, r[rt], Rt);
for (int i = head[rt]; i; i = nxt[i])
{
int v = to[i];
if (vis[v])
continue;
siz[rt] += build(v, bas, rt, Rt);
}
return siz[rt];
}
inline void rebuild(int x)
{
if (!x)
return;
clear(x, 0, dep[x]);
build(x, siz[x], f[x], f[x]);
}
inline void insert(int x, int v)
{
pa[x].insert(-v);
siz[x]++;
int Rt = 0;
for (int i = x, j; f[i]; i = j)
{
j = f[i];
int dis = bz.Dis(x, j) - v;
siz[j]++;
pa[j].insert(dis);
pb[i].insert(dis);
if (siz[i] > siz[j] * alpha)
Rt = j;
}
rebuild(Rt);
}
} t;
signed main()
{
read(), n = read();
for (int i = 1; i <= n; i++)
{
vis[i] = 1;
int fa = read() ^ lst % 1000000000, c = read();
r[i] = read();
bz.insert(i, fa, c);
if (i > 1)
{
add(fa, i);
add(i, fa);
}
t.f[i] = fa;
t.dep[i] = t.dep[fa] + 1;
write(lst += t.query(i, r[i]));
t.insert(i, r[i]);
putchar('\n');
}
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122022