1. 程式人生 > >[luogu]P3250 [HNOI2016]網路

[luogu]P3250 [HNOI2016]網路

原題連結: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 }
View Code