洛谷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;
}