[CTSC2008]網路管理Network
Description
M公司是一個非常龐大的跨國公司,在許多國家都設有它的下屬分支機構或部門。為了讓分佈在世界各地的N個部門之間協同工作,公司搭建了一個連線整個公司的通訊網路。該網路的結構由N個路由器和N-1條高速光纜組成。每個部門都有一個專屬的路由器,部門區域網內的所有機器都聯向這個路由器,然後再通過這個通訊子網與其他部門進行通訊聯絡。該網路結構保證網路中的任意兩個路由器之間都存在一條直接或間接路徑以進行通訊。 高速光纜的資料傳輸速度非常快,以至於利用光纜傳輸的延遲時間可以忽略。但是由於路由器老化,在這些路由器上進行資料交換會帶來很大的延遲。而兩個路由器之間的通訊延遲時間則與這兩個路由器通訊路徑上所有路由器中最大的交換延遲時間有關。作為M公司網路部門的一名實習員工,現在要求你編寫一個簡單的程式來監視公司的網路狀況。該程式能夠隨時更新網路狀況的變化資訊(路由器資料交換延遲時間的變化),並且根據詢問給出兩個路由器通訊路徑上延遲第k大的路由器的延遲時間。【任務】 你的程式從輸入檔案中讀入N個路由器和N-1條光纜的連線資訊,每個路由器初始的資料交換延遲時間Ti,以及Q條詢問(或狀態改變)的資訊。並依次處理這Q條詢問資訊,它們可能是: 1. 由於更新了裝置,或者裝置出現新的故障,使得某個路由器的資料交換延遲時間發生了變化。 2. 查詢某兩個路由器a和b之間的路徑上延遲第k大的路由器的延遲時間。
Input
第一行為兩個整數N和Q,分別表示路由器總數和詢問的總數。
第二行有N個整數,第i個數表示編號為i的路由器初始的資料延遲時間Ti。
緊接著N-1行,每行包含兩個整數x和y。表示有一條光纜連線路由器x和路由器y。
緊接著是Q行,每行三個整數k、a、b。
如果k=0,則表示路由器a的狀態發生了變化,它的資料交換延遲時間由Ta變為b
如果k>0,則表示詢問a到b的路徑上所經過的所有路由器(包括a和b)中延遲
第k大的路由器的延遲時間。
注意N,Q<=80000,任意一個路由器在任何時刻都滿足延遲時間小於10^8。
對於所有詢問滿足0<=K<=N
Output
對於每一個第二種詢問(k>0),輸出一行。包含一個整數為相應的延遲時間。
如果路徑上的路由器不足k個,則輸出資訊“invalidrequest!”
(全部小寫不包含引號,兩個單詞之間有一個空格)。
Sample Input
5 5
5 1 2 3 4
3 1
2 1
4 3
5 3
2 4 5
0 1 2
2 2 3
2 1 4
3 3 5
Sample Output
3
2
2
invalid request!
一句話題意:帶修改樹上路徑點權第k大
其實先做[Cqoi2011]動態逆序對再來看這題效果更好
這題其實可以樹鏈剖分+線段樹套平衡樹+二分答案,複雜度達到了\(O(n\log^4n)\),據說能過?(反正我沒寫)
其實不要這麼麻煩,我們直接把樹剖拋棄,這樣就可以達到更加優秀的複雜度
考慮不需要修改的樹上路徑第k大,直接用主席樹,查詢4條鏈,具體題目可以見Spoj 10628. Count on a tree
直接用主席樹維護其到根的路徑上的所有點,然而新增修改操作後,每次需要將子樹內全部修改,複雜度達到了\(O(n\log n)\)
考慮我們能否不去修改子樹,那麼就可以用尤拉序來維護,在尤拉序上進行差分可以直接對子樹進行修改
所以這題的做法就很明顯了,樹狀陣列套動態開點權值線段樹,樹狀陣列本質上維護dfs序的位置,在其中用線段樹進行查詢
複雜度\(O(n \log^2 n)\)
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
#define lowbit(x) ((x)&(-x))
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
int x=0,f=1; char ch=gc();
for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
inline int read(){
int x=0,f=1; char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
inline void print(int x){
if (x<0) putchar('-'),x=-x;
if (x>9) print(x/10);
putchar(x%10+'0');
}
const int N=8e4,M=2e7;
int L[N+10],R[N+10],root[(N<<1)+10],list[(N<<1)+10],v[N+10];
int n,m,T;
struct S1{
int pre[(N<<1)+10],now[N+10],child[(N<<1)+10];
int fa[N+10],top[N+10],deep[N+10],Rem[N+10],size[N+10];
int tot,Time;
void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
void insert(int x,int y){join(x,y),join(y,x);}
void dfs(int x){
deep[x]=deep[fa[x]]+1,size[x]=1;
for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
if (son==fa[x]) continue;
fa[son]=x,dfs(son);
size[x]+=size[son];
if (size[Rem[x]]<size[son]) Rem[x]=son;
}
}
void build(int x){
if (!x) return;
L[x]=++Time;
top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
build(Rem[x]);
for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
if (son==fa[x]||son==Rem[x]) continue;
build(son);
}
R[x]=Time;
}
int Lca(int x,int y){
while (top[x]!=top[y]){
if (deep[top[x]]<deep[top[y]]) swap(x,y);
x=fa[top[x]];
}
return deep[x]<deep[y]?x:y;
}
}HLD;//Heavy Light Decomposition
struct S2{
int ls[M+10],rs[M+10],cnt[M+10],A[50],B[50],tot;
void Modify(int &p,int l,int r,int x,int v){
if (!p) p=++tot;
cnt[p]+=v;
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) Modify(ls[p],l,mid,x,v);
else Modify(rs[p],mid+1,r,x,v);
}
void change(int i,int x,int v){for (;i<=n;i+=lowbit(i)) Modify(root[i],1,T,x,v);}
int Query(int x,int y,int w,int v,int k){
int cntA=0,cntB=0;
for (int i=x;i;i-=lowbit(i)) A[++cntA]=root[i];
for (int i=y;i;i-=lowbit(i)) A[++cntA]=root[i];
for (int i=w;i;i-=lowbit(i)) B[++cntB]=root[i];
for (int i=v;i;i-=lowbit(i)) B[++cntB]=root[i];
int l=1,r=T;
while (l!=r){
int mid=(l+r)>>1,res=0;
for (int i=1;i<=cntA;i++) res+=cnt[rs[A[i]]];
for (int i=1;i<=cntB;i++) res-=cnt[rs[B[i]]];
if (k<=res){
for (int i=1;i<=cntA;i++) A[i]=rs[A[i]];
for (int i=1;i<=cntB;i++) B[i]=rs[B[i]];
l=mid+1;
}else{
k-=res;
for (int i=1;i<=cntA;i++) A[i]=ls[A[i]];
for (int i=1;i<=cntB;i++) B[i]=ls[B[i]];
r=mid;
}
}
return l;
}
}V_ST;//Value_Segment Tree
struct S3{
int k,x,y;
S3(){k=x=y=0;}
void rd(){k=read(),x=read(),y=read();}
}Ask[N+10];
int main(){
n=read(),m=read(); int tot=0;
for (int i=1;i<=n;i++) list[++tot]=v[i]=read();
for (int i=1;i<n;i++){
int x=read(),y=read();
HLD.insert(x,y);
}
HLD.dfs(1),HLD.build(1);
for (int i=1;i<=m;i++){
Ask[i].rd();
if (!Ask[i].k) list[++tot]=Ask[i].y;
}
sort(list+1,list+1+tot);
T=unique(list+1,list+1+tot)-list-1;
for (int i=1;i<=n;i++) v[i]=lower_bound(list+1,list+1+T,v[i])-list;
for (int i=1;i<=m;i++) if (!Ask[i].k) Ask[i].y=lower_bound(list+1,list+1+T,Ask[i].y)-list;
for (int i=1;i<=n;i++) V_ST.change(L[i],v[i],1),V_ST.change(R[i]+1,v[i],-1);
for (int i=1;i<=m;i++){
int x=Ask[i].x,y=Ask[i].y;
if (!Ask[i].k){
V_ST.change(L[x] ,v[x],-1);
V_ST.change(R[x]+1,v[x], 1);
v[x]=y;
V_ST.change(L[x] ,v[x], 1);
V_ST.change(R[x]+1,v[x],-1);
}else{
int lca=HLD.Lca(x,y),k=Ask[i].k;
int size=HLD.deep[x]+HLD.deep[y]-2*HLD.deep[lca]+1;
if (size<k){
printf("invalid request!\n");
continue;
}
printf("%d\n",list[V_ST.Query(L[x],L[y],L[lca],L[HLD.fa[lca]],k)]);
}
}
}