【题目】
BZOJ
给定一棵
n
n
n个点的树,支持三种操作:
- 给树的一条路径打上一类标记
- 删去一类标记
- 求未经过某个点的所有标记的最大权值。
n , Q ≤ 2 × 1 0 5 n,Q\leq 2\times 10^5 n,Q≤2×105
【解题思路】
如果我们二分答案,那么问题就变成了求是否所有权值大于等于
K
K
K的路径都没有经过某个节点。
这个问题可以利用树上差分,在
(
u
,
v
)
(u,v)
(u,v)打上
+
1
+1
+1,在
l
c
a
(
u
,
v
)
lca(u,v)
lca(u,v)和
f
a
l
c
a
(
u
,
v
)
fa_{lca(u,v)}
falca(u,v)打上
−
1
-1
−1,这样节点子树和即为经过它的路径数量。
子树求和可以通过 DFS \text{DFS} DFS序转化为区间问题。
多个询问我们在外面套一个整体二分即可。
需要使用 O ( 1 ) O(1) O(1)的 l c a lca lca,复杂度 O ( n log 2 n ) O(n\log ^2 n) O(nlog2n)
还可以考虑一种更加暴力的在线做法:
我们对于每一个位置,维护一个可删除堆表示当前没有覆盖它的所有标记。
那么树链问题可以通过树剖转化为 O ( log n ) O(\log n) O(logn)个区间,我们对一条链表示的区间取反仍是个区间 O ( log n ) O(\log n) O(logn),然后每个区间在对应线段树上根到叶子的路径上的堆都插入当前标记即可。删除同理。
时间复杂度 O ( n log 2 n ) O(n\log ^2 n) O(nlog2n),空间复杂度 O ( n log 3 n ) O(n\log ^3 n) O(nlog3n),有点卡。
【参考代码】
O
(
n
log
2
n
)
O(n\log ^2 n)
O(nlog2n)
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
namespace IO
{
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
void write(int x){if(x<0)putchar('-'),x=-x;if(x>9)write(x/10);putchar(x%10^48);}
void writeln(int x){write(x);putchar('\n');}
}
using namespace IO;
namespace Tree
{
int tot,ind,cnt;
int st[N],ed[N],pos[N],dep[N],fa[N],head[N];
int f[20][N],Log[N],fc[25];
struct BIT
{
#define lowbit(x) (x&(-x))
int c[N];
void update(int x,int v){for(;x<N;x+=lowbit(x))c[x]+=v;}
int qr(int x){int res=0;for(;x;x-=lowbit(x))res+=c[x];return res;}
int query(int l,int r){return qr(r)-qr(l-1);}
#undef lowbit
}bit;
struct Tway{int v,nex;}e[N];
void add(int u,int v)
{
e[++tot]=(Tway){v,head[u]};head[u]=tot;
e[++tot]=(Tway){u,head[v]};head[v]=tot;
}
void dfs(int x)
{
st[x]=++ind;f[0][++cnt]=x;pos[x]=cnt;
for(int i=head[x];i;i=e[i].nex)
{
int v=e[i].v;
if(v==fa[x]) continue;
fa[v]=x;dep[v]=dep[x]+1;dfs(v);f[0][++cnt]=x;
}
ed[x]=ind;
}
int calc(int x,int y){return dep[x]>dep[y]?y:x;}
void buildst()
{
fc[0]=1;for(int i=1;i<=20;++i) fc[i]=fc[i-1]<<1;
for(int i=2;i<N;++i) Log[i]=Log[i>>1]+1;
for(int j=1;j<19;++j) for(int i=1;i+fc[j]-1<=cnt;++i)
f[j][i]=calc(f[j-1][i],f[j-1][i+fc[j-1]]);
}
int lca(int x,int y)
{
x=pos[x];y=pos[y];
if(x>y) swap(x,y);
int t=Log[y-x+1];
return calc(f[t][x],f[t][y-fc[t]+1]);
}
}
using namespace Tree;
namespace DreamLolita
{
int n,Q,lim;
int A[N],B[N],V[N];
struct Tquery
{
int op,id,x,ans;
bool operator <(const Tquery&rhs)const{return id<rhs.id;}
}q[N],tmp[N];
void update(int u,int v,int op)
{
int t=lca(u,v);
bit.update(st[u],op);bit.update(st[v],op);bit.update(st[t],-op);
if(fa[t]) bit.update(st[fa[t]],-op);
}
void solve(int l,int r,int L,int R)
{
if(L>R) return;
if(l==r){for(int i=L;i<=R;++i)if(q[i].op==2)q[i].ans=l;return;}
int mid=(l+r)>>1,num=0,ct=0,ql=L-1;
for(int i=L;i<=R;++i)
{
if(q[i].op==2)
{
if(bit.query(st[q[i].x],ed[q[i].x])==num) q[++ql]=q[i];
else tmp[++ct]=q[i];
}
else
{
int op=q[i].op?-1:1;
if(V[q[i].x]<=mid) q[++ql]=q[i];
else
{
tmp[++ct]=q[i];num+=op;
update(A[q[i].x],B[q[i].x],op);
}
}
}
for(int i=1;i<=ct;++i) if(tmp[i].op^2)
update(A[tmp[i].x],B[tmp[i].x],tmp[i].op?1:-1);
for(int i=1;i<=ct;++i) q[ql+i]=tmp[i];
solve(l,mid,L,ql);solve(mid+1,r,ql+1,ql+ct);
}
void solution()
{
n=read();Q=read();
for(int i=1;i<n;++i) add(read(),read());
dfs(1);buildst();
for(int i=1;i<=Q;++i)
{
q[i].op=read();q[i].id=i;
if(!q[i].op)
{
A[i]=read();B[i]=read();V[i]=read();
q[i].x=i;lim=max(lim,V[i]);
}
else q[i].x=read();
}
solve(-1,lim,1,Q);sort(q+1,q+Q+1);
for(int i=1;i<=Q;++i) if(q[i].op==2) writeln(q[i].ans);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ4538.in","r",stdin);
freopen("BZOJ4538.out","w",stdout);
#endif
DreamLolita::solution();
return 0;
}
O ( n log 3 n ) O(n\log ^3 n) O(nlog3n)
#include<bits/stdc++.h>
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef pair<int,int> pii;
const int N=2e5+10;
namespace IO
{
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
void write(int x){if(x<0)putchar('-'),x=-x;if(x>9)write(x/10);putchar(x%10^48);}
void writeln(int x){write(x);putchar('\n');}
}
using namespace IO;
namespace Data_Structure
{
struct Priority
{
priority_queue<int>q,p;
void push(int x){q.push(x);}
void erase(int x){p.push(x);}
int top()
{
while(q.size() && p.size() && q.top()==p.top()) q.pop(),p.pop();
return q.size()?q.top():-1;
}
};
struct Segment
{
#define ls (x<<1)
#define rs (x<<1|1)
Priority q[N<<1];
void update(int x,int l,int r,int L,int R,int v,int op)
{
if(L<=l && r<=R)
{
if(op) q[x].push(v); else q[x].erase(v);
return;
}
int mid=(l+r)>>1;
if(L<=mid) update(ls,l,mid,L,R,v,op);
if(R>mid) update(rs,mid+1,r,L,R,v,op);
}
int query(int x,int l,int r,int p)
{
if(l==r) return q[x].top();
int mid=(l+r)>>1;
if(p<=mid) return max(q[x].top(),query(ls,l,mid,p));
else return max(q[x].top(),query(rs,mid+1,r,p));
}
#undef ls
#undef rs
}tr;
}
using namespace Data_Structure;
namespace Tree
{
int tot,ind;
int siz[N],pos[N],top[N],son[N],dep[N],fa[N],head[N];
struct Tway{int v,nex;}e[N];
void add(int u,int v)
{
e[++tot]=(Tway){v,head[u]};head[u]=tot;
e[++tot]=(Tway){u,head[v]};head[v]=tot;
}
void dfs1(int x)
{
siz[x]=1;
for(int i=head[x];i;i=e[i].nex)
{
int v=e[i].v;
if(v==fa[x]) continue;
fa[v]=x;dep[v]=dep[x]+1;dfs1(v);siz[x]+=siz[v];
if(siz[v]>=siz[son[x]]) son[x]=v;//>= bzoj can AC,if use > MLE
}
}
void dfs2(int x,int tp)
{
pos[x]=++ind;top[x]=tp;
if(son[x]) dfs2(son[x],tp);
for(int i=head[x];i;i=e[i].nex)
{
int v=e[i].v;
if(v==fa[x] || v==son[x]) continue;
dfs2(v,v);
}
}
}
using namespace Tree;
namespace DreamLolita
{
int n,Q;
pii vec[N];
struct data
{
int x,y,v;
data(int _x=0,int _y=0,int _v=0):x(_x),y(_y),v(_v){}
}qr[N];
void solve(int x,int y,int v,int op)
{
int cnt=0;
while(top[x]^top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
vec[++cnt]=mkp(pos[top[x]],pos[x]);x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
vec[++cnt]=mkp(pos[x],pos[y]);
sort(vec+1,vec+cnt+1);
vec[0]=mkp(0,0);vec[cnt+1]=mkp(n+1,n+1);
for(int i=0;i<=cnt;++i)
{
int l=vec[i].se+1,r=vec[i+1].fi-1;
if(l<=r) tr.update(1,1,n,l,r,v,op);
}
}
void solution()
{
n=read();Q=read();
for(int i=1;i<n;++i) add(read(),read());
dfs1(1);dfs2(1,1);
for(int i=1;i<=Q;++i)
{
int op=read(),x;
if(!op)
{
qr[i].x=read();qr[i].y=read();qr[i].v=read();
solve(qr[i].x,qr[i].y,qr[i].v,1);
}
else
{
x=read();
if(op&1) solve(qr[x].x,qr[x].y,qr[x].v,0);
else printf("%d\n",tr.query(1,1,n,pos[x]));
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ4538.in","r",stdin);
freopen("BZOJ4538.out","w",stdout);
#endif
DreamLolita::solution();
return 0;
}