luogu P4175 [CTSC2008]網絡管理

Description

M 公司是一個非常龐大的跨國公司,在許多國家都設有它的下屬分支機構或部門。爲了讓分佈在世界各地的 nn 個部門之間協同工作,公司搭建了一個連接整個公司的通信網絡。

該網絡的結構由 n 個路由器和 n−1 條高速光纜組成。每個部門都有一個專屬的路由器,部門局域網內的所有機器都聯向這個路由器,然後再通過這個通信子網與其他部門進行通信聯絡。該網絡結構保證網絡中的任意兩個路由器之間都存在一條直接或間接路徑以進行通信。

高速光纜的數據傳輸速度非常快,以至於利用光纜傳輸的延遲時間可以忽略。但是由於路由器老化,在這些路由器上進行數據交換會帶來很大的延遲。而兩個路由器之間的通信延遲時間則與這兩個路由器通信路徑上所有路由器中最大的交換延遲時間有關。

作爲 M 公司網絡部門的一名實習員工,現在要求你編寫一個簡單的程序來監視公司的網絡狀況。該程序能夠隨時更新網絡狀況的變化信息(路由器數據交換延遲時間的變化),並且根據詢問給出兩個路由器通信路徑上延遲第 kk 大的路由器的延遲時間。

【任務】
你的程序從輸入文件中讀入 n 個路由器和 n−1 條光纜的連接信息,每個路由器初始的數據交換延遲時間tit_i
,以及 q 條詢問(或狀態改變)的信息。並依次處理這 q 條詢問信息,它們可能是:

1、由於更新了設備,或者設備出現新的故障,使得某個路由器的數據交換延遲時間發生了變化。

2、查詢某兩個路由器 a 和 v 之間的路徑上延遲第 k 大的路由器的延遲時間。\


Input

第一行爲兩個整數 n 和 q,分別表示路由器總數和詢問的總數。

第二行有 n 個整數,第 i 個數表示編號爲i的路由器初始的數據延遲時間 tit_i

緊接着 n−1 行,每行包含兩個整數 x 和 y。表示有一條光纜連接路由器 x 和路由器 y。

緊接着是 q 行,每行三個整數 k,a,b。

如果 k=0,則表示路由器 aa 的狀態發生了變化,它的數據交換延遲時間由 tat_a 變爲 b。

如果 k>0,則表示詢問 a 到 b 的路徑上所經過的所有路由器(包括 a 和 b)中延遲第 k 大的路由器的延遲時間。注意 a 可以等於 b,此時路徑上只有一個路由器。


Output

對於每一個第二種詢問(即 k>0 ),輸出一行。
包含一個整數爲相應的延遲時間。如果路徑上的路由器不足 k 個,則輸出信息 invalid request! 。


Solution

O(nlog2nnlog^2n)做法:

思路簡單,實現一般。

很直接地想到主席樹維護dfs序搞k大,樹鏈剖分求lca。
因爲要修改,是一段前綴和的修改,所以要用樹狀數組套主席樹。

然後就沒有然後了。。。
就是注意一下代碼的細節。

dfs序的修改保證子樹連續,所以可以通過區間修改子樹的值,而且不會影響到後面的點求值。
x-y的路徑用樹上差分算就行了,ans=v[x]+v[y]v[lca]v[f[lca]]ans=v[x]+v[y]-v[lca]-v[f[lca]]


Code

#include<bits/stdc++.h>
using namespace std;
int a[80010],b[160010],n,q,m;
int e[160010],nxt[160010],head[80010],cnt;
int top[80010],dep[80010],son[80010],fa[80010],siz[80010];
int tree[128*80010],ls[128*80010],rs[128*80010],sz;
int ln[80010],rn[80010],tot;
int rt[80010],crt[80010];
int A[160010],B[160010];
struct data{
	int k,x,y;
}qy[80010];
void add(int x,int y){
	cnt++;
	e[cnt]=y;
	nxt[cnt]=head[x];
	head[x]=cnt;
}
int find(int x){
	int l=1,r=m+1;
	while(l<r-1){
		int mid=(l+r)>>1;
		if(x>=b[mid]) l=mid;
		else r=mid;
	}
	return l;
}
void dfs1(int x,int f){
	fa[x]=f;
	siz[x]=1;
	for(int i=head[x];i;i=nxt[i]){
		int y=e[i];
		if(y==f) continue;
		dep[y]=dep[x]+1;
		dfs1(y,x);
		siz[x]+=siz[y];
		if(siz[y]>siz[son[x]])
		son[x]=y;
	}
}
void dfs2(int x,int tp){
	if(x==0) return;
	top[x]=tp;
	ln[x]=++tot;
	dfs2(son[x],tp);
	for(int i=head[x];i;i=nxt[i])
	if(top[e[i]]==0) dfs2(e[i],e[i]);
	rn[x]=tot;
}
int lca(int x,int y){
	while(top[x]!=top[y]){
		if(x==0) exit(0);
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	return x;
}
void ins(int &x,int l,int r,int d,int v){
	sz++;
	ls[sz]=ls[x];
	rs[sz]=rs[x];
	tree[sz]=tree[x]; 
	x=sz,tree[x]+=v;
	if(l==r) return;
	int mid=(l+r)>>1;
	if(d<=mid) ins(ls[x],l,mid,d,v);
	else ins(rs[x],mid+1,r,d,v);
}
void build(int x){
	rt[x]=rt[fa[x]];
	ins(rt[x],1,m,a[x],1);//從fa轉移到x
	if(son[x]==0) return;
	build(son[x]);
	for(int i=head[x];i;i=nxt[i])
	if(e[i]!=fa[x]&&e[i]!=son[x])
	build(e[i]); 
}
int lowbit(int x){
	return x&-x;
}
void upt(int x,int d,int v){
	for(int i=x;i<=tot;i+=lowbit(i))
	ins(crt[i],1,m,d,v);
}
bool check(int k){
	long long sum=0;
	for(int i=1;i<=A[0];i++) sum+=tree[A[i]];
	for(int i=1;i<=B[0];i++) sum-=tree[B[i]];
	return sum>=k;
}
void query(int k,int x,int y){
	A[0]=B[0]=0;
	int f=lca(x,y);
	A[++A[0]]=rt[x],A[++A[0]]=rt[y];
	B[++B[0]]=rt[f],B[++B[0]]=rt[fa[f]];
	for(int i=ln[x];i;i-=lowbit(i)) A[++A[0]]=crt[i]; //因爲dfs序子樹連續纔可以這樣寫
	for(int i=ln[y];i;i-=lowbit(i)) A[++A[0]]=crt[i];
	for(int i=ln[f];i;i-=lowbit(i)) B[++B[0]]=crt[i];
	for(int i=ln[fa[f]];i;i-=lowbit(i)) B[++B[0]]=crt[i];
	if(check(k)==0){
		printf("invalid request!\n");
		return;
	}
	int l=1,r=m;
	while(l<r){
		int mid=(l+r)>>1;
		long long sum=0;
		for(int i=1;i<=A[0];i++) sum+=tree[rs[A[i]]];
		for(int i=1;i<=B[0];i++) sum-=tree[rs[B[i]]];
		if(k>sum){
			for(int i=1;i<=A[0];i++) A[i]=ls[A[i]];
			for(int i=1;i<=B[0];i++) B[i]=ls[B[i]];
			k-=sum,r=mid;
		}
		else{
			for(int i=1;i<=A[0];i++) A[i]=rs[A[i]];
			for(int i=1;i<=B[0];i++) B[i]=rs[B[i]];
			l=mid+1;
		}
	}
	printf("%d\n",b[l]);
}
int main(){
	int k,x,y,t=0;
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[++t]=a[i];
	}
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}
	dfs1(1,0),dfs2(1,1);
	for(int i=1;i<=q;i++){
		scanf("%d%d%d",&qy[i].k,&qy[i].x,&qy[i].y);
		if(qy[i].k==0) b[++t]=qy[i].y;
	}
	sort(b+1,b+t+1);
	m=unique(b+1,b+t+1)-b-1;
	for(int i=1;i<=n;i++) 
	a[i]=find(a[i]);;
	build(1);
	for(int i=1;i<=q;i++){
		k=qy[i].k,x=qy[i].x,y=qy[i].y;
		if(k==0){
			upt(ln[x],a[x],-1);
			upt(rn[x]+1,a[x],1);//保證不影響後面的點
			a[x]=find(y);
			upt(ln[x],a[x],1);
			upt(rn[x]+1,a[x],-1);
		}
		else query(k,x,y);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章