线段树上二分+链交+LCA
这题做法大概有2种,我用的是第二种
1.实际上一条链的贡献是这条链在树上的补集,于是树剖线段树维护树,每一个节点开一个堆维护最大贡献。 O(nlog3n)
2.假设对于一个询问x,二分出一个答案C,若所有≥C的链都经过了x,则显然最终答案<C,否则最终答案≥C。于是离线将所有链按权排序后,建立权值线段树,节点存储子节点的链交,直接在线段树上二分找答案即可, O(nlog2n) ,如果把LCA优化成O(1)即可做到 O(nlogn) 。
顺便补充一下如何求链交,网络上求链交的看不懂,于是只好自己脑补一个。
记链为(LCA,a,b),a,b为两端点,链的深度指LCA的深度,定义max(a,b)为取a,b中深度大的,lca(a,b)为取a,b的LCA。
先判断有没有交,方法是判断深度大链的LCA在不在深度小的链上,若不在则无交集。
否则有交,
若LCA1 = LCA2 ,链交的LCA不变,两端点分别取max即可,就不详细说了。
若LCA1 ≠ LCA2,根据脑补+画图可以知道链交的两个端点分别是
a = max( lca(a1,b2), lca(a2,b1) )
b = max( lca(a1,a2), lca(b1,b2) )
这个式子应该具有一般性,可以直接套用(只是常数比较大)
#include<cstdio>
#include<algorithm>
#define N 200005
#define H 20
#define reg register
using namespace std;
namespace runzhe2000
{
const int INF = 1<<30;
int ecnt, last[N], cnt, timer, beg[N], end[N], fa[N], dep[N], list[N*4], que[N], ST[N*4][H], pos[N], log[N*4], bin[H];
struct edge{int next,to;}e[N<<1];
struct opt
{
int type, a, b, v;
}q[N];
struct chain
{
int lca, a, b;
inline bool in(reg int x)
{
if(lca == 0)return false;
else if(lca == -1)return true;
return beg[lca] <= beg[x] && beg[x] <= end[lca] &&( (beg[x] <= beg[a] && beg[a] <= end[x]) || (beg[x] <= beg[b] && beg[b] <= end[x]) );
}
};
struct seg
{
int l, r, v, tot;
chain c;
}t[N*5];
bool cmp(int a, int b){return q[a].v < q[b].v;}
void addedge(reg int a, reg int b)
{
e[++ecnt] = (edge){last[a], b};
last[a] = ecnt;
}
inline int dep_min(reg int x, reg int y){return dep[x] < dep[y] ? x : y;}
inline int dep_max(reg int x, reg int y){return dep[x] > dep[y] ? x : y;}
void dfs(int x)
{
dep[x] = dep[fa[x]] + 1;
list[++timer] = x;
beg[x] = timer;
for(int i = last[x]; i; i = e[i].next)
{
int y = e[i].to;
if(y == fa[x])continue;
fa[y] = x;
dfs(y);
list[++timer] = x;
}
end[x] = timer;
}
void build_ST()
{
dep[0] = INF;
bin[0] = 1;for(int i = 1; i < H; i++)bin[i] = bin[i-1] << 1;
for(reg int i = 2; i <= timer; i++)log[i] = 1 + log[i>>1];
for(reg int i = 1; i <= timer; i++)ST[i][0] = list[i];
for(reg int j = 1; j < H; j++)
for(reg int i = 1; i <= timer; i++)
ST[i][j] = dep_min(ST[i][j-1], ST[i+bin[j-1]][j-1]);
}
int ask_lca(reg int x, reg int y)
{
if(x==y)return x;
reg int a = beg[x], b = beg[y];
if(a>b)swap(a,b);
reg int len = b-a+1;
return dep_min(ST[a][log[len]], ST[b-bin[log[len]]+1][log[len]]);
}
void pushup(int x)
{
int lson = x<<1, rson = x<<1|1, u, v;
if(t[lson].c.lca == -1)t[x].c = t[rson].c;
else if(t[rson].c.lca == -1)t[x].c = t[lson].c;
else if(t[lson].c.lca == 0 || t[rson].c.lca == 0)t[x].c = (chain){0,0,0};
else if(!t[lson].c.in(t[rson].c.lca) && !t[rson].c.in(t[lson].c.lca))t[x].c = (chain){0,0,0};
else if(t[lson].c.lca == t[rson].c.lca)
{
u = dep_max(ask_lca(t[lson].c.a, t[rson].c.a), ask_lca(t[lson].c.a, t[rson].c.b));
v = dep_max(ask_lca(t[lson].c.b, t[rson].c.a), ask_lca(t[lson].c.b, t[rson].c.b));
t[x].c = (chain){t[lson].c.lca, u, v};
}
else
{
u = dep_max(ask_lca(t[lson].c.a, t[rson].c.b), ask_lca(t[lson].c.b, t[rson].c.a));
v = dep_max(ask_lca(t[lson].c.a, t[rson].c.a), ask_lca(t[lson].c.b, t[rson].c.b));
t[x].c = (chain){ask_lca(u, v), dep_min(u,v), dep_max(u,v)};
}
if(t[x].c.lca==-1 || t[x].c.lca==0)t[x].v=-1;
else t[x].v=max(t[lson].v, t[rson].v);
t[x].tot = t[x<<1].tot + t[x<<1|1].tot;
}
void build(int x, int l, int r)
{
t[x].l = l;
t[x].r = r;
t[x].c = (chain){t[x].v = -1,0,0};
t[x].tot = 0;
if(l==r)return;
int mid = (l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
void modify(reg int x, reg int p, reg int id)
{
if(t[x].l==t[x].r)
{
if(!id)t[x].c = (chain){-1,0,0}, t[x].v=-1, t[x].tot = 0;
else t[x].c = (chain){ask_lca(q[id].a, q[id].b), q[id].a, q[id].b}, t[x].v=q[id].v, t[x].tot = 1;
return;
}
int mid = (t[x].l+t[x].r)>>1;
if(p<=mid)modify(x<<1,p,id);
else modify(x<<1|1,p,id);
pushup(x);
}
int query(reg int x, reg int p)
{
if(t[x].l == t[x].r)return t[x].c.in(p)?-1:t[x].v;
else if(!t[x<<1|1].c.in(p))return query(x<<1|1,p);
else return query(x<<1,p);
}
void main()
{
int n, m;
scanf("%d%d",&n,&m);
for(reg int i = 1, a, b; i < n; i++)
{
scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);
}
dfs(1);
build_ST();
for(reg int i = 1; i <= m; i++)
{
scanf("%d",&q[i].type);
if(q[i].type == 0)
{
que[++cnt] = i;
scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].v);
}
else if(q[i].type == 1)
scanf("%d",&q[i].v);
else
scanf("%d",&q[i].v);
}
sort(que+1,que+cnt+1,cmp);
for(reg int i = 1; i <= cnt; i++)pos[que[i]] = i;
if(cnt)build(1,1,cnt);
for(reg int i = 1; i <= m; i++)
{
if(q[i].type == 0)
modify(1,pos[i],i);
else if(q[i].type == 1)
modify(1,pos[q[i].v],0);
else
{
if(!t[1].tot || t[1].c.in(q[i].v))printf("-1\n");
else printf("%d\n",query(1,q[i].v));
}
}
}
}
int main()
{
runzhe2000::main();
}