原题链接:P3250 [HNOI2016]网络
题意
给定一棵无根树,m个操作
0操作:增加一条a到b的权值为v的链
1操作:删除第t个操作
2操作:输出不经过x节点的权值最大的链
分析
数据结构神题。。。
题目中要求维护不经过$x$节点的权值最大值,也就是说所有不经过$x$节点的链都能对答案产生贡献。
也就是说,当增加一条链的时,除了链上的点,都应该增加价值为$v$的权值,答案就转化为了$x$点上的最大权值。
我们可以线段树套堆……
每个区间开一个堆,堆内存这段区间的权值。
我们注意到堆需要支持删除操作。
如何支持删除呢,我们可以开一个删除标志,维护每一个堆需要开两个堆,一个堆用于存插入的数据,另一个堆是已经被删掉的数据。
如果两个堆顶一样,就一起$pop$掉,不然就输出第一个堆的堆顶。
如果第一个堆为空输出$-1$。
由于堆的操作比较慢,而且插入和删除的操作区间是一样的,我这里直接标记永久化免去了下推标记操作。
代码
1 #include <bits/stdc++.h> 2 const int N=2*1e5+1009; 3 using namespace std; 4 int read(){ 5 char c;int num,f=1; 6 while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0'; 7 while(c=getchar(), isdigit(c))num=num*10+c-'0'; 8 return f*num; 9 } 10 struct Heap{ 11 priority_queue<int>rl,dl; 12 void push(int x){rl.push(x);} 13 void del(int x){ 14 dl.push(x); 15 while(!dl.empty()&&dl.top()==rl.top()){ 16 dl.pop();rl.pop(); 17 } 18 } 19 int top(){ 20 while(!dl.empty()&&dl.top()==rl.top()){ 21 dl.pop();rl.pop(); 22 } 23 if(rl.empty())return -1; 24 return rl.top(); 25 } 26 }tree[N*5]; 27 struct link{ 28 int x,y,v; 29 }lk[N],tmp[N]; 30 int n,m; 31 int head[N],nxt[N*2],ver[N*2],tot=1; 32 int son[N],fa[N],siz[N],id[N],dep[N],top[N],tott=0; 33 void DFS1(int x,int pre,int deep){ 34 dep[x]=deep;siz[x]=1; 35 for(int i=head[x];i;i=nxt[i]){ 36 if(ver[i]==pre)continue; 37 DFS1(ver[i],x,deep+1); 38 fa[ver[i]]=x; 39 siz[x]+=siz[ver[i]]; 40 if(siz[ver[i]]>siz[son[x]])son[x]=ver[i]; 41 } 42 } 43 void DFS2(int x,int ltp){ 44 id[x]=++tott; 45 top[x]=ltp; 46 if(!son[x])return ; 47 DFS2(son[x],ltp); 48 for(int i=head[x];i;i=nxt[i]){ 49 if(ver[i]==fa[x]||ver[i]==son[x])continue; 50 DFS2(ver[i],ver[i]); 51 } 52 } 53 //树链剖分 54 55 void modify(int l,int r,int L,int R,int rt,int opt,int xx){ 56 if(L<=l&&r<=R){ 57 opt?tree[rt].del(xx):tree[rt].push(xx); 58 return ; 59 } 60 int mid=(l+r)>>1; 61 if(L<=mid)modify(l,mid,L,R,rt<<1,opt,xx); 62 if(mid< R)modify(mid+1,r,L,R,rt<<1|1,opt,xx); 63 } 64 int query(int l,int r,int x,int rt){ 65 if(l==r)return tree[rt].top(); 66 int mid=(l+r)>>1,ans=tree[rt].top(); 67 if(x<=mid)return max(ans,query(l,mid,x,rt<<1)); 68 else return max(ans,query(mid+1,r,x,rt<<1|1)); 69 } 70 void add_edge(int u,int v){ 71 ver[++tot]=v;nxt[tot]=head[u];head[u]=tot; 72 ver[++tot]=u;nxt[tot]=head[v];head[v]=tot; 73 } 74 void Swap(int &x,int &y){x^=y;y^=x;x^=y;} 75 bool cmp(link x,link y){ 76 if(x.x!=y.x)return x.x<y.x; 77 return x.y<y.y; 78 } 79 void link_modify(int u,int v,int val,int opt){ 80 int cnt=0; 81 while(top[u]!=top[v]){ 82 if(dep[top[u]]<dep[top[v]])Swap(u,v); 83 tmp[++cnt].x=id[top[u]]; 84 tmp[ cnt].y=id[u]; 85 u=fa[top[u]]; 86 } 87 if(id[u]>id[v])Swap(u,v); 88 tmp[++cnt].x=id[u]; 89 tmp[ cnt].y=id[v]; 90 sort(tmp+1,tmp+1+cnt,cmp); 91 int maxn=0; 92 for(int i=1;i<=cnt;maxn=max(maxn,tmp[i++].y)) 93 if(maxn+1<tmp[i].x)modify(1,n,maxn+1,tmp[i].x-1,1,opt,val); 94 if(maxn<n)modify(1,n,maxn+1,n,1,opt,val); 95 } 96 int main() 97 { 98 n=read();m=read(); 99 for(int i=1;i< n;i++)add_edge(read(),read()); 100 DFS1(1,1,1);DFS2(1,1); 101 for(int i=1;i<=m;i++){ 102 int opt=read(); 103 if(opt==0){ 104 lk[i].x=read(); 105 lk[i].y=read(); 106 lk[i].v=read(); 107 link_modify(lk[i].x,lk[i].y,lk[i].v,opt); 108 }else if(opt==1){ 109 int ttt=read(); 110 link_modify(lk[ttt].x,lk[ttt].y,lk[ttt].v,opt); 111 }else { 112 int a=read(); 113 printf("%d\n",query(1,n,id[a],1)); 114 } 115 } 116 return 0; 117 }