版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvzelong2014/article/details/85683658
bzoj4538: [Hnoi2016]网络
分析
二分最大值呗。
相当于把所有大于这个值的路径筛出来啦。
链修改,点查询->点修改,子树查询。
就是
,
判断某那个点是否经过当前所有链即可。
整体二分上一下即可。
代码
#include<bits/stdc++.h>
const int N = 1e5 + 10, M = 2e5 + 10;
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int pr[N], to[M], nx[M], in[N], out[N], t[N], fa[N], id[M], ans[M], tot, tp, n, mx, cnt;
int p1[M], tp1, p2[M], tp2;
void add(int u, int v) {to[++tp] = v; nx[tp] = pr[u]; pr[u] = tp;}
void adds(int u, int v) {add(u, v); add(v, u);}
namespace LCA {
int bin[21], ps[N], Lg[M], mn[21][M], tot;
int Be(int u, int v) {return ps[u] < ps[v] ? u : v;}
void Pre() {
bin[0] = 1; for(int i = 1;i <= 20; ++i) bin[i] = bin[i - 1] << 1;
Lg[0] = -1; for(int i = 1;i <= tot; ++i) Lg[i] = Lg[i >> 1] + 1;
for(int j = 1;bin[j] <= tot; ++j)
for(int i = 1;i + bin[j] - 1 <= tot; ++i)
mn[j][i] = Be(mn[j - 1][i], mn[j - 1][i + bin[j - 1]]);
}
int Lca(int u, int v) {
u = ps[u]; v = ps[v];
if(u > v) std::swap(u, v);
int t = Lg[v - u + 1];
return Be(mn[t][u], mn[t][v - bin[t] + 1]);
}
}
void Dfs(int u, int fa) {
using namespace LCA;
in[u] = ++::tot; ::fa[u] = fa;
mn[0][++LCA::tot] = u; ps[u] = LCA::tot;
for(int i = pr[u]; i; i = nx[i])
if(to[i] != fa) {
Dfs(to[i], u);
mn[0][++LCA::tot] = u;
}
out[u] = ::tot;
}
struct Data {
int tp, u, v, val;
void In() {
tp = ri();
if(!tp) u = ri(), v = ri(), val = ri(), mx = std::max(mx, val);
else u = ri();
}
}ev[M], op[M];
void Add(int x, int w) {
for(;x <= n; x += x &-x)
t[x] += w;
}
int Que(int x) {
int r = 0;
for(;x; x -= x&-x)
r += t[x];
return r;
}
void Ins(int u, int v, int w) {
cnt += w;
int c = LCA::Lca(u, v);
Add(in[u], w); Add(in[v], w);
Add(in[c], -w); if(fa[c]) Add(in[fa[c]], -w);
}
int Query(int u) {return Que(out[u]) - Que(in[u] - 1);}
void Solve(int L, int R, int st, int ed) {
if(st > ed) return ;
if(L == R) {
for(int i = st;i <= ed; ++i)
if(ev[id[i]].tp == 2)
ans[id[i]] = L;
return ;
}
int m = L + R >> 1, tp1 = 0, tp2 = 0;
for(int i = st;i <= ed; ++i) {
Data u = ev[id[i]];
if(!u.tp) {
if(u.val > m)
Ins(u.u, u.v, 1), p1[tp1++] = id[i];
else p2[tp2++] = id[i];
}
else if(u.tp == 1) {
Data v = ev[u.u];
if(v.val > m)
Ins(v.u, v.v, -1), p1[tp1++] = id[i];
else p2[tp2++] = id[i];
}
else
Query(u.u) != cnt ? p1[tp1++] = id[i] : p2[tp2++] = id[i];
}
for(int i = 0;i < tp1; ++i) { //restore
Data u = ev[p1[i]];
if(!u.tp)
Ins(u.u, u.v, -1);
else if(u.tp == 1) {
Data v = ev[u.u];
Ins(v.u, v.v, 1);
}
}
for(int i = 0;i < tp2; ++i)
id[st + i] = p2[i];
for(int i = 0;i < tp1; ++i)
id[st + tp2 + i] = p1[i];
Solve(L, m, st, st + tp2 - 1);
Solve(m + 1, R, st + tp2, ed);
}
int main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n = ri(); int m = ri();
for(int i = 1;i < n; ++i)
adds(ri(), ri());
Dfs(1, 0); LCA::Pre();
for(int i = 1;i <= m; ++i) ev[i].In(), id[i] = i;
Solve(0, mx, 1, m);
for(int i = 1;i <= m; ++i)
if(ev[i].tp == 2)
printf("%d\n", ans[i] ?: -1);
return 0;
}