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

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

Sample Output

-1
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
",ans[id[i]]);
	return 0;
}

  

原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5466287.html