题目链接 SP2939 QTREE5 - Query on a tree V
我们要求某点到最近白点的距离,支持多次修改多次询问。
如果这题换成了最长距离,那么显然就没有这层关系了,我们就考虑这道题的动态点分治的做法。
查询答案
如果现在的点的答案在目前点分树内,那么距离就一定是“该点到该点分树树根的距离”+“该点分树树根到最近白点的距离”。那么,有的人就会问了,如果在这个点分树到它的点分子树中间的路径上的话,那么距离不就是被扩大了嘛(比真实值要大的意思)。那好,我们来解释一下这个问题,如果说,在目前点分树中的答案算得到的距离是偏大的,那么也就是说它在上一个点分子树里面,那么也就是说,我们在上一棵点分树中已经算过了它的贡献了。所以说,不存在“偏大答案”被选取的情况,因为它在没“偏大”之前就已经被算掉了。
更新数据
用一个小根堆来维护,也就是值小的在前,支持删除、插入操作,那么可以自己模拟一个堆(heap英文:堆)。然后不断的更新该点到目前点分树树根的距离,是删除还是插入。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define Big_INF 0x3f3f3f3f3f3f3f3f
#define eps 1e-6
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
inline int read()
{
int x=0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x;
}
const int maxN = 1e5 + 7;
int N, Q, head[maxN], cnt, LOG_2[maxN << 1];
struct Eddge
{
int nex, to;
Eddge(int a=-1, int b=0):nex(a), to(b) {}
} edge[maxN << 1];
inline void addEddge(int u, int v)
{
edge[cnt] = Eddge(head[u], v);
head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
struct Grand_Father
{
int deep[maxN], euler[maxN << 1], Esiz, rid[maxN];
void dfs(int u, int fa)
{
deep[u] = deep[fa] + 1; rid[u] = Esiz + 1;
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == fa) continue;
euler[++Esiz] = u;
dfs(v, u);
}
euler[++Esiz] = u;
}
int mn[maxN << 1][20];
inline void RMQ_Init()
{
for(int i=1; i<=Esiz; i++) mn[i][0] = euler[i];
for(int j=1; (1 << j) <= Esiz; j++)
{
for(int i=1; i + (1 << j) - 1 <= Esiz; i++)
{
if(deep[mn[i][j - 1]] < deep[mn[i + (1 << (j - 1))][j - 1]]) mn[i][j] = mn[i][j - 1];
else mn[i][j] = mn[i + (1 << (j - 1))][j - 1];
}
}
}
inline int Rmq(int l, int r)
{
int det = r - l + 1, kk = LOG_2[det];
if(deep[mn[l][kk]] <= deep[mn[r - (1 << kk) + 1][kk]]) return mn[l][kk];
else return mn[r - (1 << kk) + 1][kk];
}
inline int _LCA(int u, int v)
{
int l = rid[u], r = rid[v];
if(l > r) swap(l, r);
return Rmq(l, r);
}
inline int _Dis(int u, int v)
{
int lca = _LCA(u, v);
return deep[u] + deep[v] - 2 * deep[lca];
}
} A_lca;
struct heap
{
priority_queue<int, vector<int> , greater<int> > Que, Del;
inline bool empty()
{
while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
return Que.empty();
}
inline void push(int val) { Que.push(val); }
inline void clear(int val) { Del.push(val); }
inline int size() { return (int)(Que.size() - Del.size()); }
inline int top()
{
while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
return Que.top();
}
inline void pop()
{
while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
Que.pop();
}
} s[maxN];
int white_num = 0;
int siz[maxN], all, son[maxN], maxx, root, father[maxN];
bool vis[maxN] = {false};
void findroot(int u, int fa)
{
siz[u] = 1; son[u] = 0;
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(vis[v] || v == fa) continue;
findroot(v, u);
siz[u] += siz[v];
son[u] = max(son[u], siz[v]);
}
son[u] = max(son[u], all - siz[u]);
if(son[u] < maxx) { maxx = son[u]; root = u; }
}
void Divide(int u)
{
vis[u] = true;
int totsiz = all;
for(int i=head[u], v, rt; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(vis[v]) continue;
all = siz[v] > siz[u] ? totsiz - siz[u] : siz[v];
maxx = INF;
findroot(v, 0);
father[root] = u;
rt = root;
Divide(root);
}
}
bool white[maxN] = {false};
inline void update(int u)
{
int cop_u = u, dt;
white[u] ^= 1;
if(white[u])
{
white_num ++;
while(u)
{
dt = A_lca._Dis(u, cop_u);
s[u].push(dt);
u = father[u];
}
}
else
{
white_num --;
while(u)
{
dt = A_lca._Dis(u, cop_u);
s[u].clear(dt);
u = father[u];
}
}
}
inline int query(int u)
{
int cop_u = u, dt, ans = INF;
while(u)
{
dt = A_lca._Dis(u, cop_u);
if(!s[u].empty()) ans = min(ans, dt + s[u].top());
u = father[u];
}
return ans;
}
inline void init()
{
cnt = 0;
for(int i=1; i<=N; i++) head[i] = -1;
for(int i = 1, j = 2, k = 0; i<=(N << 1); i++)
{
if(i == j) { j <<= 1; k ++; }
LOG_2[i] = k;
}
}
int main()
{
N = read();
init();
for(int i=1, u, v; i<N; i++)
{
u = read(); v = read();
_add(u, v);
}
A_lca.dfs(1, 0);
A_lca.RMQ_Init();
all = N; maxx = INF;
findroot(1, 0);
Divide(root);
Q = read();
int x, op;
while(Q--)
{
op = read(); x = read();
if(op)
{
if(!white_num) printf("-1\n");
else printf("%d\n", query(x));
}
else
{
update(x);
}
}
return 0;
}