洛谷3250 网络(树链剖分+堆)

传送门

【题目分析】

维护非常巧妙。。。。看了看网上的做法才知道每个节点可以维护一个堆qwq

每次询问相当于求不经过该点路径的最大权值,所以考虑每次加入一条路径的时候,将除这条路径上的所有点更新即可。

所以就用堆来维护。。。开两个堆,一个维护压入堆的元素,一个维护出堆的元素,查询时就从top开始往下找直到第一个不同的地方或者出堆的size为0。

【代码~】

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const int MAXM=2e5+10;

int n,q,cnt;
int head[MAXN],depth[MAXN],top[MAXN],siz[MAXN],fa[MAXN],son[MAXN];
int nxt[MAXM],to[MAXM];
int dfn[MAXN],ys[MAXN],tot;
pair<int,int> p[MAXN];
struct Edge{
	int nxt,to;
}edge[MAXM];
struct Path{
	int from,to,w;
}path[MAXN<<1];
struct Tree{
	int l,r;
	priority_queue<int> a,b;
	void add(int x){
		a.push(x);
	}
	void del(int x){
		b.push(x);
	}
	int top(){
		while(!b.empty()&&a.top()==b.top()){
			a.pop(),b.pop();
		}
		if(!a.empty())
		  return a.top();
		return -1;
	}
}tr[MAXN<<2];

int Read(){
	int i=0,f=1;
	char c;
	for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
	if(c=='-')
	  f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())
	  i=(i<<3)+(i<<1)+c-'0';
	return i*f;
}

void add(int x,int y){
	edge[++cnt]=(Edge){head[x],y},head[x]=cnt;
	edge[++cnt]=(Edge){head[y],x},head[y]=cnt;
}

void dfs1(int u,int f){
	siz[u]=1;
	for(int i=head[u];i!=-1;i=edge[i].nxt){
		int v=edge[i].to;
		if(v==f)
		  continue;
		depth[v]=depth[u]+1,fa[v]=u;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[v]>=siz[son[u]])
		  son[u]=v;
	}
}

void dfs2(int u,int tp){
	top[u]=tp;
	dfn[u]=++tot;
	if(!son[u])
	  return ;
	dfs2(son[u],tp);
	for(int i=head[u];i!=-1;i=edge[i].nxt){
		int v=edge[i].to;
		if(v==fa[u]||v==son[u])
		  continue;
		dfs2(v,v);
	}
}

void update(int root,int l,int r,int L,int R,int key,int type){
	if(l==L&&r==R){
		if(type)
		  tr[root].add(key);
		else
		  tr[root].del(key);
		return ;
	}
	int mid=l+r>>1;
	if(R<=mid)
	  update(root<<1,l,mid,L,R,key,type);
	else{
		if(L>mid)
		  update(root<<1|1,mid+1,r,L,R,key,type);
		else
		  update(root<<1,l,mid,L,mid,key,type),update(root<<1|1,mid+1,r,mid+1,R,key,type);
	}
}

int query(int root,int l,int r,int x){
	if(l==r)
	  return tr[root].top();
	int mid=l+r>>1;
	if(x<=mid)
	  return max(tr[root].top(),query(root<<1,l,mid,x));
	else
	  return max(tr[root].top(),query(root<<1|1,mid+1,r,x));
}

void updatepath(int x,int y,int key,int type){
	int sum=0;
	while(top[x]!=top[y]){
		if(depth[top[x]]<depth[top[y]])
		  swap(x,y);
		p[++sum]=make_pair(dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	if(depth[x]>depth[y])
	  swap(x,y);
	p[++sum]=make_pair(dfn[x],dfn[y]);
	sort(p+1,p+sum+1);
	p[0]=make_pair(0,0);
	p[sum+1]=make_pair(n+1,n+1);
	for(int i=0;i<=sum;++i){
		int l=p[i].second+1,r=p[i+1].first-1;
		if(l<=r)
		  update(1,1,n,l,r,key,type);
	}
}

int main(){
	memset(head,-1,sizeof(head));
	n=Read(),q=Read();
	for(int i=1;i<n;++i){
		int x=Read(),y=Read();
		add(x,y);
	}
	dfs1(1,-1);
	dfs2(1,1);
	for(int i=1;i<=q;++i){
		int cz=Read();
		if(cz==0){
			path[i].from=Read();
			path[i].to=Read();
			path[i].w=Read();
			updatepath(path[i].from,path[i].to,path[i].w,1);
		}
		else{
			if(cz==1){
				int x=Read();
				updatepath(path[x].from,path[x].to,path[x].w,0);
			}
			else{
				int x=Read();
				cout<<query(1,1,n,dfn[x])<<'\n';
			}
		}
	}
	return 0;
}

 

posted @ 2018-11-02 21:02  Ishtar~  阅读(141)  评论(0编辑  收藏  举报