[bzoj1146] [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!
Solution
單點修改鏈上第\(k\)大。
由於我太弱了,想不到正解,就只能暴力維護這個東西了
很自然的可以想到用樹剖維護,然後區間第\(k\)大是用的線段樹套平衡樹,那麼這裡就全套起來,然後複雜度到了驚人的\(O(m\log^4n)\)。
最騷的是這玩意可以妥妥的過。\(bzoj\)只用了\(25s\),\(luogu\)最慢的點也只有\(1500ms\)。
碼量適中,解法自然,給出題人點贊
然而我碼了\(5k+\)。。。
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 8e4+1;
int son[maxn*100][2],sz[maxn*100],val[maxn*100],tot,cnt[maxn*100],rd[maxn*100],re[maxn],dfn[maxn];
int v[maxn],n,Q;
struct pii{int fr,sc;};
struct Fhq_Treap {
int rt;
void update(int x) {sz[x]=sz[son[x][0]]+sz[son[x][1]]+cnt[x];}
int newnode(int x) {val[++tot]=x,sz[tot]=cnt[tot]=1;rd[tot]=rand();return tot;}
int merge(int x,int y) {
if(!x||!y) return x+y;
if(rd[x]>rd[y]) return son[x][1]=merge(son[x][1],y),update(x),x;
else return son[y][0]=merge(x,son[y][0]),update(y),y;
}
pii split(int x,int k) {
if(!x) return (pii){0,0};
if(sz[son[x][0]]>=k) {
pii now=split(son[x][0],k);
son[x][0]=now.sc,now.sc=x,update(x);return now;
} else {
pii now=split(son[x][1],k-sz[son[x][0]]-cnt[x]);
son[x][1]=now.fr,now.fr=x,update(x);return now;
}
}
int find(int x,int k,int &bo,int delta,int e) {
int ans=0;if(!x) return 0;
if(k<val[x]) ans=find(son[x][0],k,bo,delta,e);
else if(k==val[x]) {
if(delta!=-1||cnt[x]!=1) cnt[x]+=delta,sz[x]+=delta,bo=1;
ans=sz[son[x][0]]+e*cnt[x];return ans;
} else ans=find(son[x][1],k,bo,delta,e)+sz[son[x][0]]+cnt[x];
if(bo) sz[x]+=delta;return ans;
}
void insert(int x) {
if(!rt) return rt=newnode(x),void();
int bo=0,k=find(rt,x,bo,1,0);if(bo) return ;
pii now=split(rt,k);rt=merge(now.fr,merge(newnode(x),now.sc));
}
void erase(int x) {
int bo=0,k=find(rt,x,bo,-1,1);if(bo) return ;
pii now=split(rt,k),now2=split(now.fr,k-1);rt=merge(now2.fr,now.sc);
}
int kth(int x) { // how many number are bigger than x
int bo=0,k=sz[rt]-find(rt,x,bo,0,1);return k;
}
};
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
struct Segment_Tree {
Fhq_Treap s[maxn<<2];
void modify(int p,int l,int r,int x,int pre,int now) {
s[p].erase(pre),s[p].insert(now);
if(l==r) return ;
if(x<=mid) modify(ls,l,mid,x,pre,now);
else modify(rs,mid+1,r,x,pre,now);
}
int query(int p,int l,int r,int x,int y,int k) {
if(x<=l&&r<=y) return s[p].kth(k);
int ans=0;
if(x<=mid) ans+=query(ls,l,mid,x,y,k);
if(y>mid) ans+=query(rs,mid+1,r,x,y,k);
return ans;
}
void build(int p,int l,int r) {
for(int i=l;i<=r;i++) s[p].insert(v[re[i]]);
if(l==r) return ;build(ls,l,mid),build(rs,mid+1,r);
}
}SGT;
#undef ls
#undef rs
#undef mid
struct Heavy_Light_Decomposation {
struct edge{int to,nxt;}e[maxn<<1];
int head[maxn],cnt,hs[maxn],top[maxn],fa[maxn],sz[maxn],dep[maxn],dfn_cnt;
void add(int u,int vv) {e[++cnt]=(edge){vv,head[u]},head[u]=cnt;}
void ins(int u,int vv) {add(u,vv),add(vv,u);}
void dfs(int x,int f) {
sz[x]=1,dep[x]=dep[f]+1,fa[x]=f;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=f) {
dfs(e[i].to,x),sz[x]+=sz[e[i].to];
if(sz[e[i].to]>sz[hs[x]]) hs[x]=e[i].to;
}
}
void dfs2(int x) {
dfn[x]=++dfn_cnt,re[dfn_cnt]=x;
if(hs[fa[x]]==x) top[x]=top[fa[x]];
else top[x]=x;
if(hs[x]) dfs2(hs[x]);
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa[x]&&e[i].to!=hs[x]) dfs2(e[i].to);
}
int lca(int x,int y) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}if(dep[x]>dep[y]) swap(x,y);return x;
}
int calc(int x,int y,int k) {
int ans=0;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=SGT.query(1,1,n,dfn[top[x]],dfn[x],k);
x=fa[top[x]];
}if(dep[x]>dep[y]) swap(x,y);
ans+=SGT.query(1,1,n,dfn[x],dfn[y],k);
return ans;
}
void solve(int x,int y,int k) {
if((dep[x]+dep[y]-2*dep[lca(x,y)]+1)<k)
return puts("invalid request!"),void();
int l=0,r=1e8,mid,ans=0;
while(l<=r) {
mid=((l+r)>>1);
int t=calc(x,y,mid);
if(t<=k-1) ans=mid,r=mid-1;
else l=mid+1;
}write(ans);
}
}HLD;
int main() {
read(n),read(Q);
for(int i=1;i<=n;i++) read(v[i]);
for(int i=1,x,y;i<n;i++) read(x),read(y),HLD.ins(x,y);
HLD.dfs(1,0),HLD.dfs2(1);SGT.build(1,1,n);
for(int k,a,b,i=1;i<=Q;i++) {
read(k),read(a),read(b);
if(!k) SGT.modify(1,1,n,dfn[a],v[a],b),v[a]=b;
else HLD.solve(a,b,k);
}
return 0;
}