P3250 [HNOI2016]网络

链接

一个很暴力的做法是直接树剖,对除路径上 \(\log n\) 个区间之外的加入决策,很明显要修改的区间也有 \(\log n\) 个,因为要支持删除,所以每个节点要加一个延迟删除的堆来维护,时间复杂度 \(O(n \log^3 n)\)

发现决策会维持一段区间,可以用线段树分治,于是节点上可以不用堆而只用一个单调栈维护,复杂度 \(O(n \log^3 n)\)

考虑二分一个值 \(val\) ,将 \(v \geq val\) 的路径上的节点加一,如果询问节点值等于加入路径的值,则 \(ans < val\),否则 \(ans \geq val\)
于是差分 \(+\) 整体二分,树状数组维护即可,复杂度 \(O(n \log^2 n)\)

#include<bits/stdc++.h>
#define IL inline
#define LL long long
using namespace std;
const int N=2e5+3;
struct kk{
  int to,nxt;
}e[N<<1];
struct hh{
  int op,id,x,y,lca,v;
}q[N],ql[N],qr[N];
int n,m,num,cnt,b[N],fir[N],ans[N];
int siz[N],dep[N],dfn[N],top[N],son[N],fa[N];
IL int in(){
  char c;int f=1;
  while((c=getchar())<'0'||c>'9')
    if(c='-') f=-1;
  int x=c-'0';
  while((c=getchar())>='0'&&c<='9')
    x=x*10+c-'0';
  return x*f;
}
IL void add(int x,int y){e[++num]=(kk){y,fir[x]},fir[x]=num;}
void dfs1(int u,int f){
  siz[u]=1,dep[u]=dep[f]+1,fa[u]=f;
  for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
    if(v^f){
		  dfs1(v,u),siz[u]+=siz[v];
		  if(siz[son[u]]<siz[v]) son[u]=v;
		}
}
void dfs2(int u,int t){
  dfn[u]=++num,top[u]=t;
  if(son[u]) dfs2(son[u],t);
  for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
    if(v^fa[u]&&v^son[u]) dfs2(v,v);
}
IL int Lca(int x,int y){
  while(top[x]^top[y]) dep[top[x]]<dep[top[y]]?y=fa[top[y]]:x=fa[top[x]];
  return dep[x]<dep[y]?x:y;
}
struct BIT{
  int c[N];
  IL int lb(int x){return x&-x;}
  IL void add(int y,int x){for(;y<=n;y+=lb(y)) c[y]+=x;}
  IL int ask(int y){int res=0;for(;y;y-=lb(y)) res+=c[y];return res;}
  IL void mdy(hh a,int v){
		add(dfn[a.x],v),add(dfn[a.y],v),add(dfn[a.lca],-v);
		if(a.lca^1) add(dfn[fa[a.lca]],-v);
	}
	IL int query(int x){return ask(dfn[x]+siz[x]-1)-ask(dfn[x]-1);}
}T;
void solve(int l,int r,int ll,int rr){
  if(ll>rr) return;
  int c=0;
  if(l==r){
	  for(int i=ll;i<=rr;++i)
	    if(q[i].op^2) T.mdy(q[i],q[i].op?-1:1),c+=q[i].op?-1:1;
	    else ans[q[i].id]=(T.query(q[i].x)^c?b[l]:-1);
	  for(int i=ll;i<=rr;++i) if(q[i].op^2) T.mdy(q[i],q[i].op?1:-1);
	  return;
	}
	int mid=l+r>>1,nl=0,nr=0;
	for(int i=ll;i<=rr;++i)
	  if(q[i].op^2){
		  if(q[i].v>mid) T.mdy(q[i],q[i].op?-1:1),c+=q[i].op?-1:1,qr[++nr]=q[i];
		  else ql[++nl]=q[i];
		}
	  else if(T.query(q[i].x)^c) qr[++nr]=q[i];
	  else ql[++nl]=q[i];
	for(int i=ll;i<=rr;++i) if(q[i].op^2&&q[i].v>mid) T.mdy(q[i],q[i].op?1:-1);
	for(int i=1;i<=nl;++i) q[ll+i-1]=ql[i];
	for(int i=1;i<=nr;++i) q[ll+nl+i-1]=qr[i];
	solve(l,mid,ll,ll+nl-1),solve(mid+1,r,ll+nl,rr);
}
int main()
{
	//freopen("1.in","r",stdin);
	int op,x,y,z;
	n=in(),m=in();
	for(int i=1;i<n;++i)
	  x=in(),y=in(),
	  add(x,y),add(y,x);
	num=0,dfs1(1,0),dfs2(1,1);
	for(int i=1;i<=m;++i){
	  op=in();
	  if(!op) x=in(),y=in(),q[i]=(hh){op,i,x,y,Lca(x,y),b[++cnt]=in()},ans[i]=-2;
	  else if(op==1) x=in(),q[i]=q[x],q[i].op=1,ans[i]=-2;
	  else q[i]=(hh){op,i,in(),0,0,0};
	}
	sort(b+1,b+cnt+1),cnt=unique(b+1,b+cnt+1)-b-1;
	for(int i=1;i<=m;++i) if(q[i].op^2) q[i].v=lower_bound(b+1,b+cnt+1,q[i].v)-b;
	solve(1,cnt,1,m);
	for(int i=1;i<=m;++i) if(ans[i]^-2) printf("%d\n",ans[i]);
  return 0;
}
posted @ 2020-11-21 19:07  (o-ωq)).oO  阅读(105)  评论(0编辑  收藏  举报