【BZOJ4538】【HNOI2016】—网络(树链剖分+可删堆)

传送门

题意:给定一棵树,支持添加一条路径,删除一条路径,询问不经过某一点的路径中的最大值

考虑到删除和询问最大值普通线段树很难维护
考虑把线段树上每个节点设成一个可删堆
就可以方便的维护删除和最大值了

由于询问“不经过某一点”的最大值,我们修改就对于整棵树关于这条路径的补集修改

由于路径的区间是 O ( l o g n ) O(logn) O(logn)个,那么补集也是有 O ( l o g n ) O(logn) O(logn)个,排序之后依次修改就是了

复杂度 O ( n l o g 2 n l o g l o g n ) O(nlog^2nlog_{logn}) O(nlog2nloglogn)

开始总是T飞,把重儿子那里的 > > >改成>=就过了

U p d a t e Update Update:
L e o Leo Leo说那是一组神仙数据,能把以 1 1 1为根的链式前向星做法的 l o g log log卡满……,需要随机剖分一下

#include
using namespace std;
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res*f;
}
const int N=100005;
int adj[N],nxt[N<<1],to[N<<1],cnt,dfn,pos[N],dep[N],n,m;
int siz[N],fa[N],son[N],top[N];
struct heap{
	priority_queue<int>A,B;
	inline void push(int x){
		A.push(x);
	}
	inline void erase(int x){
		B.push(x);
	}
	inline int top(){
		while(B.size()&&A.top()==B.top())
			A.pop(),B.pop();
		return A.empty()?-1:A.top();
	}
}tr[N<<2];
struct ask{
	int u,v,k;
}q[N<<1];
pair<int,int>p[N];
#define se second
#define fi first
inline void addedge(int u,int v){
	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
}
void dfs1(int u){
	siz[u]=1,son[u]=0;
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(v==fa[u])continue;
		fa[v]=u,dep[v]=dep[u]+1;
		dfs1(v),siz[u]+=siz[v];
		if(siz[v]>=siz[son[u]])son[u]=v;//就这里,别问我为什么,我也不知道
	}
}
void dfs2(int u,int tp){
	pos[u]=++dfn,top[u]=tp;
	if(!son[u])return;
	dfs2(son[u],tp);
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(v==son[u]||v==fa[u])continue;
		dfs2(v,v);
	}
}
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
inline void update(int u,int l,int r,int st,int des,int k,int op){
	if(st<=l&&r<=des){
		if(op)tr[u].push(k);
		else tr[u].erase(k);
		return;
	}
	if(st<=mid)update(lc,l,mid,st,des,k,op);
	if(mid<des)update(rc,mid+1,r,st,des,k,op);
}
inline int query(int u,int l,int r,int pos){
	if(l==r)return tr[u].top();
	if(pos<=mid)return max(tr[u].top(),query(lc,l,mid,pos));
	else return max(tr[u].top(),query(rc,mid+1,r,pos));
}
inline void pathupdate(int u,int v,int k,int op){
	int tot=0;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		p[++tot]=make_pair(pos[top[u]],pos[u]);
		u=fa[top[u]];
	}
	if(dep[u]>dep[v])swap(u,v);
	p[++tot]=make_pair(pos[u],pos[v]);
	sort(p+1,p+tot+1);
	p[0]=make_pair(0,0),p[tot+1]=make_pair(n+1,n+1);
	for(int i=0;i<=tot;i++){
		int l=p[i].se+1,r=p[i+1].fi-1;
		if(l<=r)update(1,1,n,l,r,k,op);
	}
}
int main(){
//	freopen("lx.cpp","r",stdin);
	n=read(),m=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		addedge(u,v),addedge(v,u);
	}
	dfs1(1),dfs2(1,1);
	for(int i=1;i<=m;i++){
		int op=read();
		switch(op){
			case 0:{
				q[i].u=read(),q[i].v=read(),q[i].k=read();
				pathupdate(q[i].u,q[i].v,q[i].k,1);
				break;
			}
			case 1:{
				int p=read();
				pathupdate(q[p].u,q[p].v,q[p].k,0);
				break;
			}
			case 2:{
				int x=read();
				cout<<query(1,1,n,pos[x])<<'\n';
				break;
			}
		}
	}
}

你可能感兴趣的:(树链剖分,线段树)