LWDB
题意:
给一棵 $n$ 个节点的树,维护两种操作:
1.将距离 $x$ $distance \leq d$ 的点染成 $c$
2.询问 $x$ 的颜色。
解法:
首先将染色可以转换为每个时间对应一个颜色,问题转化为区间取 $max$
动态树分治,即可。
考虑朴素点分治中的每一个重心,将其管辖的所有点按照到重心的距离从大到小排序,然后用线段树维护。
修改时,从 $x$ 向上走,将每一个重心 $t$ 中 $dist<x,t> + dist<t,y>\leq d$ 的点修改。
查找时,从 $x$ 向上走,查询每一个重心中 $x$ 所对应的值,求 $max$ 即可。
$O(nlog^2n)$
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #define p E[i].x #define N 100010 #define M 7000010 #define l(x) ch[x][0] #define r(x) ch[x][1] #define MP(x, y) make_pair(x, y) #define LL long long using namespace std; typedef pair<int,int> PII; struct edge { int x, to, v; }E[N<<1]; int totE, totn, n, m, hev, lef_now; int g[N], h[N], de[N], siz[N], root[N], fa[N][21], col[N], d[N]; int ch[M][2], setv[M]; vector<PII> nod[N], id[N]; vector<int> hevs[N]; int dis[N][21]; bool v[N]; void addedge(int x, int y, int v) { E[++totE] = (edge){y, g[x], v}; g[x] = totE; } int build(int l, int r) { int x = ++totn; setv[x] = 0; if(l == r) return x; int mid = (l+r)>>1; l(x) = build(l, mid); r(x) = build(mid+1, r); return x; } void push(int x) { if(!setv[x]) return; setv[l(x)] = setv[x]; setv[r(x)] = setv[x]; setv[x] = 0; } int ask(int x, int l, int r, int qx) { if(l<r) push(x); if(l == r) return setv[x]; int mid = (l+r)>>1; if(qx <= mid) return ask(l(x), l, mid, qx); else return ask(r(x), mid+1, r, qx); } void change(int x, int l, int r, int ql, int qr, int qv) { if(l<r) push(x); if(ql<=l && r<=qr) { setv[x] = qv; return; } int mid=(l+r)>>1; if(ql <= mid) change(l(x),l,mid,ql,qr,qv); if(mid < qr) change(r(x),mid+1,r,ql,qr,qv); } int dist(int x, int y) { if(de[x] < de[y]) swap(x, y); int ans = 0; for(int i = 20;~i;i--) if(de[fa[x][i]] >= de[y]) ans += dis[x][i], x = fa[x][i]; if(x == y) return ans; for(int i = 20;~i;i--) if(fa[x][i] != fa[y][i]) { ans += dis[x][i]; x = fa[x][i]; ans += dis[y][i]; y = fa[y][i]; } return ans+dis[x][0]+dis[y][0]; } void dfs1(int x, int tmp) { siz[x] = 1; h[x] = 0; for(int i = g[x];i;i = E[i].to) if(!v[p] && p != tmp) { dfs1(p, x); h[x] = max(h[x], siz[p]); siz[x] += siz[p]; } h[x] = max(h[x], lef_now - siz[x]); if(!hev || h[x] < h[hev]) hev = x; } void dfs(int x) { for(int i = g[x];i;i = E[i].to) if(p != fa[x][0]) { fa[p][0] = x; dis[p][0] = E[i].v; de[p] = de[x] + 1; dfs(p); } } void dfs2(int x, int tmp, int now) { nod[now].push_back(MP(d[x], x)); for(int i = g[x];i;i = E[i].to) if(!v[p] && p != tmp) { d[p] = d[x] + E[i].v; dfs2(p, x, now); } } void solve(int x) { v[x] = 1; d[x] = 0; dfs2(x, x, x); sort(nod[x].begin(), nod[x].end()); for(int i = 0;i < (int)nod[x].size();i++) { id[x].push_back( MP(nod[x][i].second, i) ); hevs[nod[x][i].second].push_back(x); } sort(id[x].begin(), id[x].end()); root[x] = build(0, nod[x].size()-1); for(int i = g[x];i;i = E[i].to) if(!v[p]) { hev = 0; lef_now = siz[p]; dfs1(p, x); solve(hev); } } int find(int x,int len) { int l=0,r=nod[x].size()-1; while(r-l>4) { int mid = (l+r)>>1; if(nod[x][mid].first <= len) l=mid; else r=mid; } for(int i=r;i>=l;i--) if(nod[x][i].first <= len) return i; return -1; } void com_change(int x, int len, int v) { for(int i = 0;i < (int)hevs[x].size();i++) { int tmp = hevs[x][i]; int t = find(tmp, len - dist(x, tmp)); if(t == -1) continue; change(root[tmp], 0, id[tmp].size()-1, 0, t, v); } } int com_ask(int x) { int ans = 0; for(int i = 0;i < (int)hevs[x].size();i++) { int tmp = hevs[x][i]; int t = (*lower_bound(id[tmp].begin(), id[tmp].end(), MP(x, -1))).second; ans = max(ans, ask(root[tmp], 0, id[tmp].size()-1, t)); } return col[ans]; } int main() { scanf("%d", &n); for(int i = 1, x, y, v;i < n;i++) { scanf("%d %d %d", &x, &y, &v); addedge(x, y, v); addedge(y, x, v); } de[1]=1; dfs(1); for(int j = 1;j <= 20;j++) { for(int i = 1;i <= n;i++) { fa[i][j] = fa[fa[i][j-1]][j-1]; dis[i][j] = dis[fa[i][j-1]][j-1] + dis[i][j-1]; } } totn = 0; hev = 0; lef_now = n; dfs1(1, 1); solve(hev); scanf("%d", &m); int x,cmd,len,tot=0; while(m--) { scanf("%d%d",&cmd,&x); if(cmd==1) { scanf("%d%d",&len,&col[++tot]); com_change(x,len,tot); } else printf("%d\n",com_ask(x)); } return 0; }