BZOJ4538: [Hnoi2016]网络
Description
一个简单的网络系统可以被描述成一棵无根树。每个节点为一个服务器。连接服务器与服务器的数据线则看做
一条树边。两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有服务器(包括这两个服务
器自身)。由于这条路径是唯一的,当路径上的某个服务器出现故障,无法正常运行时,数据便无法交互。此外,
每个数据交互请求都有一个重要度,越重要的请求显然需要得到越高的优先处理权。现在,你作为一个网络系统的
管理员,要监控整个系统的运行状态。系统的运行也是很简单的,在每一个时刻,只有可能出现下列三种事件中的
一种:1. 在某两个服务器之间出现一条新的数据交互请求;2. 某个数据交互结束请求;3. 某个服务器出现故
障。系统会在任何故障发生后立即修复。也就是在出现故障的时刻之后,这个服务器依然是正常的。但在服务器产
生故障时依然会对需要经过该服务器的数据交互请求造成影响。你的任务是在每次出现故障时,维护未被影响的请
求中重要度的最大值。注意,如果一个数据交互请求已经结束,则不将其纳入未被影响的请求范围。
Input
第一行两个正整数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
Output
对于每个type=2的事件,即服务器出现故障的事件,输出一行一个整数,描述未被影响的请求中重要度的最大
值。如果此时没有任何请求,或者所有请求均被影响,则输出-1。
Sample Input
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
Sample Output
3
5
-1
1
-1
1
1
3
6
7
7
4
6
HINT
样例给出的树如下所示:
解释其中的部分询问;下面的解释中用(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。
这道题有很多做法,我只用了感觉比较好写的一种。
考虑整体二分,问题转化成对于每个点计算是否有不包括它的线段,容斥一下计算有多少条包含它的线段,dfs序+树状数组做做就行了。
时间复杂度为O(Mlog^N)。
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-'0'; return x*f; } typedef long long ll; const int maxn=100010; const int maxm=200010; int n,m,first[maxn],next[maxn<<1],to[maxn<<1],e; void AddEdge(int u,int v) { to[++e]=v;next[e]=first[u];first[u]=e; to[++e]=u;next[e]=first[v];first[v]=e; } int st[maxn],en[maxn],dep[maxn],anc[maxn][20],cnt; void dfs(int x,int fa) { st[x]=++cnt;anc[x][0]=fa;dep[x]=dep[fa]+1; rep(i,1,19) anc[x][i]=anc[anc[x][i-1]][i-1]; for(int i=first[x];i;i=next[i]) if(to[i]!=fa) dfs(to[i],x); en[x]=cnt; } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); dwn(i,19,0) if((1<<i)<=dep[x]-dep[y]) x=anc[x][i]; dwn(i,19,0) if(anc[x][i]!=anc[y][i]) x=anc[x][i],y=anc[y][i]; return x==y?x:anc[x][0]; } int sumv[maxn],clo[maxn],T; void add(int x,int v) { if(!x) return; for(;x<=n;x+=x&-x) { if(clo[x]==T) sumv[x]+=v; else clo[x]=T,sumv[x]=v; } } int sum(int x) { int res=0; for(;x;x-=x&-x) if(clo[x]==T) res+=sumv[x]; return res; } int ans[maxm],yes[maxm],qx[maxm],id[maxm],ty[maxm],Q[maxm]; struct Oper { int x,y,v,z; int l,r; bool operator < (const Oper& ths) const {return v<ths.v;} }A[maxm]; struct Solver { int tp,p,x,v,v2; bool operator < (const Solver& ths) const {return p<ths.p;} }B[maxn*5]; int tmp[maxm]; void solve(int L,int R,int f,int h) { if(f>h) return; if(L+1==R) { rep(i,f,h) if(ans[id[Q[i]]]>=0) ans[id[Q[i]]]=A[L].v; return; } int mid=L+R>>1,N=0,cur=0; rep(i,mid,R) { B[++N]=(Solver){0,A[i].l,A[i].x,1,1}; B[++N]=(Solver){0,A[i].l,A[i].y,1,0}; B[++N]=(Solver){0,A[i].l,A[i].z,-1,0}; B[++N]=(Solver){0,A[i].l,anc[A[i].z][0],-1,0}; if(A[i].r<=m){ B[++N]=(Solver){0,A[i].r,A[i].x,-1,-1}; B[++N]=(Solver){0,A[i].r,A[i].y,-1,0}; B[++N]=(Solver){0,A[i].r,A[i].z,1,0}; B[++N]=(Solver){0,A[i].r,anc[A[i].z][0],1,0}; } } rep(i,f,h) if(ans[id[Q[i]]]>=0) B[++N]=(Solver){1,id[Q[i]],qx[Q[i]],i,0}; sort(B+1,B+N+1);T++; rep(i,1,N) { if(!B[i].tp) add(st[B[i].x],B[i].v),cur+=B[i].v2; else yes[B[i].v]=!(sum(en[B[i].x])-sum(st[B[i].x]-1)==cur); } int l=f,r=h; rep(i,f,h) { if(!yes[i]) tmp[l++]=Q[i]; else tmp[r--]=Q[i]; } rep(i,f,h) Q[i]=tmp[i]; solve(L,mid,f,r);solve(mid,R,l,h); } int main() { n=read();m=read(); rep(i,2,n) AddEdge(read(),read()); int N=0,M=0,cur=0; dfs(1,0); rep(i,1,m) { int tp=read(); if(!tp) { N++;A[N].x=read(),A[N].y=read(),A[N].z=lca(A[N].x,A[N].y); add(st[A[N].x],1);add(st[A[N].y],1); add(st[A[N].z],-1);add(st[anc[A[N].z][0]],-1); A[N].v=read();A[N].l=i;A[N].r=m+1;ty[i]=N;cur++; } else if(tp==1) { int x=ty[read()]; A[x].r=i; add(st[A[x].x],-1);add(st[A[x].y],-1); add(st[A[x].z],1);add(st[anc[A[x].z][0]],1);cur--; } else { qx[++M]=read(),id[M]=i; if(sum(en[qx[M]])-sum(st[qx[M]]-1)==cur) ans[i]=-1; } Q[i]=i; } sort(A+1,A+N+1); solve(1,N+1,1,M); rep(i,1,M) printf("%d\n",ans[id[i]]); return 0; }