[HNOI2016]網絡
題目描述
一個簡單的網絡系統可以被描述成一棵無根樹。每個節點為一個服務器。連接服務器與服務器的數據線則看做一條樹邊。兩個服務器進行數據的交互時,數據會經過連接這兩個服務器的路徑上的所有服務器(包括這兩個服務器自身)。
由於這條路徑是唯一的,當路徑上的某個服務器出現故障,無法正常運行時,數據便無法交互。此外,每個數據交互請求都有一個重要度,越重要的請求顯然需要得到越高的優先處理權。現在,你作為一個網絡系統的管理員,要監控整個系統的運行狀態。系統的運行也是很簡單的,在每一個時刻,只有可能出現下列三種事件中的一種:
-
在某兩個服務器之間出現一條新的數據交互請求;
-
某個數據交互結束請求;
- 某個服務器出現故障。系統會在任何故障發生後立即修復。也就是在出現故障的時刻之後,這個服務器依然是正常的。但在服務器產生故障時依然會對需要經過該服務器的數據交互請求造成影響。
你的任務是在每次出現故障時,維護未被影響的請求中重要度的最大值。註意,如果一個數據交互請求已經結束,則不將其納入未被影響的請求範圍。
輸入輸出格式
輸入格式:第一行兩個正整數n,m,分別描述服務器和事件個數。服務器編號是從1開始的,因此n個服務器的編號依次是1,2,3,...,n。
接下來n-1行,每行兩個正整數u,v,描述一條樹邊。u和v是服務器的編號。
接下來m行,按發生時刻依次描述每一個事件;即第i行(i=1,2,3,...,m)描述時刻i發生的事件。每行的第一個數type描述事件類型,共3種類型:
(1)若type=0,之後有三個正整數a,b,v,表示服務器a,b之間出現一條重要度為v的數據交互請求;
(2)若type=1,之後有一個正整數t,表示時刻t(也就是第t個發生的事件)出現的數據交互請求結束;
(3)若type=2,之後有一個正整數x,表示服務器x在這一時刻出現了故障。
對於每個type為2的事件,就是一次詢問,即詢問”當服務器x發生故障時,未被影響的請求中重要度的最大值是多少?“註意可能有某個服務器自身與自身進行數據交互的情況。2 <= n <= 10^5, 1 <= m <= 2×10^5,其他的所有輸入值不超過 10^9
輸出格式:對於每個type=2的事件,即服務器出現故障的事件,輸出一行一個整數,描述未被影響的請求中重要度的最大值。如果此時沒有任何請求,或者所有請求均被影響,則輸出-1。
輸入輸出樣例
輸入樣例#1: 復制13 23 1 2 1 3 2 4 2 5 3 6 3 7 4 8 4 9 6 10 6 11 7 12 7 13 2 1 0 8 13 3 0 9 12 5 2 9 2 8 2 2 0 10 12 1 2 2 1 3 2 7 2 1 0 9 5 6 2 4 2 5 1 7 0 9 12 4 0 10 5 7 2 1 2 4 2 12 1 2 2 5 2 3輸出樣例#1: 復制
-1 3 5 -1 1 -1 1 1 3 6 7 7 4 6
說明
樣例給出的樹如下所示:
解釋其中的部分詢問;下面的解釋中用(a,b;t,v)表示在t時刻出現的服務器a和b之間的重
要度為v的請求:
對於第一個詢問(在時刻1),此時沒有任何請求,輸出-1。
對於第四個詢問(在時刻6),此時有兩條交互(8,13;2,3),(9,12;3,5),所有詢問均經過2
號服務器,輸出-1。
對於第五個詢問(在時刻8),此時有三條交互(8,13;2,3),(9,12;3,5),(10,12;7,1),只有交互
(10,12;7,1)沒有經過2號服務器,因此輸出其重要度1。
對於最後一個詢問(在時刻23),此時有三條交互(9,5;12,6),(9,12;16,4),(10,5;17,7)。當3
號服務器出現故障時,只有交互(9,5;12,6)沒有經過3號服務器,因此輸出6。
solution:首先將無根樹進行樹鏈剖分,因為我們操作時需要尋找路徑。
對於操作一只需要在線段樹上將重要值push進不在任務路徑上的點,操作二同操作一,不過是把值push進對應點的刪除堆,操作三詢問線段樹,對於每個結點比較插入堆和刪除堆是否相等,若相等就都pop出去,不相等就輸出插入堆頂。
#include<bits/stdc++.h> #define N 100010 using namespace std; int n,m,u,v,w,x,opt,cnt,tim,ans; int head[N],fa[N],son[N],top[N],sz[N],dep[N],pos[N],id[N]; struct tree{ priority_queue<int>q1,q2; void push1(int a){q1.push(a);} void push2(int a){q2.push(a);} int top() { while((!q2.empty())&&(q1.top()==q2.top()))q1.pop(),q2.pop(); if(!q1.empty())return q1.top(); else return -1; } }sgm[N<<2]; struct node{ int next,to; }e[N<<2]; struct query{ int from,to,val; }q[N*2]; struct stock{ int l,r; }lian[N]; bool cmp(const stock&a,const stock&b) { return a.l<b.l; } void add(int u,int v) { e[++cnt].next=head[u],e[cnt].to=v,head[u]=cnt; } void dfs1(int u,int f,int d)//剖出重兒子 { fa[u]=f,dep[u]=d,sz[u]=1; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(v==f)continue; dfs1(v,u,d+1); sz[u]+=sz[v]; if(!son[u]||sz[v]>sz[son[u]])son[u]=v; } } void dfs2(int u,int tp)//剖出重鏈 { top[u]=tp,pos[u]=++tim,id[tim]=u;//top保存鏈頂,pos保存結點在線段樹中的位置 if(!son[u])return ; dfs2(son[u],tp);//優先重兒子 for(int i=head[u];i;i=e[i].next) if(e[i].to!=fa[u]&&e[i].to!=son[u])dfs2(e[i].to,e[i].to); } void update(int rt,int l,int r,int L,int R,int k) { if(L<=l&&R>=r) { if(!opt)sgm[rt].push1(k);//插入堆 else sgm[rt].push2(k);//插入刪除堆 return ; } int mid=(l+r)>>1; if(L<=mid)update(rt<<1,l,mid,L,R,k); if(R>mid)update(rt<<1|1,mid+1,r,L,R,k); } void query(int rt,int l,int r,int x) { if(l==r){ans=max(ans,sgm[rt].top());return ;} int mid=(l+r)>>1; if(x<=mid)query(rt<<1,l,mid,x); else query(rt<<1|1,mid+1,r,x); } void find(int u,int v,int val)//找路徑 { int f1=top[u],f2=top[v],tot=0; while(f1!=f2)//先跳到同一條鏈 { if(dep[f1]<dep[f2])swap(f1,f2),swap(u,v); lian[++tot].l=pos[f1],lian[tot].r=pos[u]; u=fa[f1],f1=top[u]; } if(dep[u]<dep[v])swap(u,v); lian[++tot].l=pos[v],lian[tot].r=pos[u]; sort(lian+1,lian+1+tot,cmp); int last=0; for(int i=1;i<=tot;i++) { if(last+1<=lian[i].l-1)update(1,1,n,last+1,lian[i].l-1,val); last=lian[i].r; } if(last+1<=n)update(1,1,n,last+1,n,val); } int read() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f*=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int main() { n=read(),m=read(); for(int i=1;i<=n-1;i++)u=read(),v=read(),add(u,v),add(v,u); dfs1(1,1,1),dfs2(1,1); for(int i=1;i<=m;i++) { opt=read(); if(opt==0) { q[i].from=read(),q[i].to=read(),q[i].val=read(); find(q[i].from,q[i].to,q[i].val); } else if(opt==1) { x=read(); find(q[x].from,q[x].to,q[x].val); } else if(opt==2) { ans=-1; x=read();query(1,1,n,pos[x]); printf("%d\n",ans); } } return 0; }
[HNOI2016]網絡