bzoj3083 遙遠的國度

2021-07-29 03:47:36 字數 3777 閱讀 4408

傳送門

description

描述 zcwwzdjn在追殺十分sb的zhx,而zhx逃入了乙個遙遠的國度。當zcwwzdjn準備進入遙遠的國度繼續追殺時,守護神rapid阻攔了zcwwzdjn的去路,他需要zcwwzdjn完成任務後才能進入遙遠的國度繼續追殺。

問題是這樣的:遙遠的國度有n個城市,這些城市之間由一些路連線且這些城市構成了一顆樹。這個國度有乙個首都,我們可以把這個首都看做整棵樹的根,但遙遠的國度比較奇怪,首都是隨時有可能變為另外乙個城市的。遙遠的國度的每個城市有乙個防禦值,有些時候rapid會使得某兩個城市之間的路徑上的所有城市的防禦值都變為某個值。rapid想知道在某個時候,如果把首都看做整棵樹的根的話,那麼以某個城市為根的子樹的所有城市的防禦值最小是多少。由於rapid無法解決這個問題,所以他攔住了zcwwzdjn希望他能幫忙。但zcwwzdjn還要追殺sb的zhx,所以這個重大的問題就被轉交到了你的手上。

input

第1行兩個整數n m,代表城市個數和運算元。

第2行至第n行,每行兩個整數 u v,代表城市u和城市v之間有一條路。

第n+1行,有n個整數,代表所有點的初始防禦值。

第n+2行乙個整數 id,代表初始的首都為id。

第n+3行至第n+m+2行,首先有乙個整數opt,如果opt=1,接下來有乙個整數id,代表把首都修改為id;如果opt=2,接下來有三個整數p1 p2 v,代表將p1 p2路徑上的所有城市的防禦值修改為v;如果opt=3,接下來有乙個整數 id,代表詢問以城市id為根的子樹中的最小防禦值。

output

對於每個opt=3的操作,輸出一行代表對應子樹的最小點權值。

sample input

3 71 2

1 31 2 3

3 12 1 1 6

3 12 2 2 5

3 12 3 3 4

3 1sample output

提示對於20%的資料,n<=1000 m<=1000。

對於另外10%的資料,n<=100000,m<=100000,保證修改為單點修改。

對於另外10%的資料,n<=100000,m<=100000,保證樹為一條鏈。

對於另外10%的資料,n<=100000,m<=100000,沒有修改首都的操作。

對於100%的資料,n<=100000,m<=100000,0《所有權值<=2^31。

hint

source

zhonghaoxi提供

這道題乍一看僅僅是一道樹鏈剖分,但是讀過題後發現這道題非常毒瘤,因為這道題需要支援換根。

換根?每次重新dfs、建立線段樹不就好了麼?

然而題目的範圍是100000,顯然是不行的。

那該怎麼辦呢?

我們可以想到,僅僅保留真實情況下根的位置,而事實上並不去動原樹,在詢問的時候按照真實的根來查詢。查詢時的情況分三類:

①根和當前點重合,直接輸出整個線段樹中的最小值。

②根和當前點的lca就是當前點,也就是說根在當前點的子樹中,這樣的話我們只需要查詢線段樹中去除當前點包含根的兒子那一部分的最小值。(蒟蒻開始只會列舉所有可能的位置,兩個點無限t飛qaq)

③其他情況直接輸出以當前點為根的子樹的最小值。

其他的操作就是樹剖的普通操作。

有乙個小小的坑點:本題的資料範圍是0~2^31-1,結果我已開始用的inf=1e9,wa了4個點

ps:我竟然沒有發現乙個人直接利用樹剖性質來求lca的,全都用的倍增,那讓我來給各位科普一下吧。花式找lca

在cogs上的提交,23333

code:

#includeconst

int inf=2147483647;

const

int n=1e5+10;

struct edge

a[n<<1];

struct tree

t[n<<2];

int head[n],size[n],son[n],deep[n],pos[n],top[n],f[n],s[n],num[n];

int n,q,x,y,z,opt,e_num,tot,root;

inline int max(int a,int b)

inline int min(int a,int b)

inline void read(int &n)

inline void add(int x,int y)

void dfs(int

now,int fa,int depth)

}void dfs2(int

now,int high)

inline void pushdown(int l,int r,int

now)

inline void update(int

now)

void build(int l,int r,int

now)

intmid=(l+r)>>1;

build(l,mid,now

<<1);

build(mid+1,r,now

<<1|1);

update(now);

}void add(int l,int r,int l,int r,int

now,int num)

intmid=(l+r)>>1;

pushdown(l,r,now);

if(l<=mid) add(l,r,l,mid,now

<<1,num);

if(r>mid) add(l,r,mid+1,r,now

<<1|1,num);

update(now);

}int ask(int l,int r,int l,int r,int

now)

void addpath(int x,int y,int z)

if(deep[top[x]]1,n,1,z);

return addpath(y,f[top[x]],z);

}inline int lca(int x,int y)

inline int ask(int x)

if(pos[from]>1) ans=min(ans,ask(1,pos[from]-1,1,n,1));

if(pos[from]+size[from]<=n) ans=min(ans,ask(pos[from]+size[from],n,1,n,1));

return ans;

}return ask(pos[x],pos[x]+size[x]-1,1,n,1);

}int main()

return 0;

}

原本列舉所有情況的醜陋**qaq:

inline int ask(int

x) if(pos[from]>1) ans=min(ans,ask(1,pos[from]-1,1,n,1));

if(pos[from]+size[from]<=n) ans=min(ans,ask(pos[from]+size[from],n,1,n,1));

//for(int i=head[x];i;i=a[i].next)

// if(lca(a[i].to,root)==a[i].to)

// while(x)

//

return ans;

}return ask(pos[x],pos[x]+size[x]-1,1,n,1);

}

bzoj3083 遙遠的國度

題意 給定一棵樹,支援換根,路徑權值覆蓋,求子樹最小。思路 求子樹?上樹鏈剖分,但是換根怎麼辦?我們只能通過原有資訊推出換根後的答案。換根不影響路徑修改,所以只要考慮子樹最小值的維護。這裡要分3種情況討論 1 如果詢問點是當前根,直接返回整棵樹的最小值。2 如果在原樹中,當前根不在 x的子樹中,直接...

bzoj3083 遙遠的國度

time limit 10 sec memory limit 1280 mb submit 1733 solved 429 submit status discuss description 描述 zcwwzdjn在追殺十分sb的zhx,而zhx逃入了乙個遙遠的國度。當zcwwzdjn準備進入遙遠的...

bzoj3083 遙遠的國度

time limit 10 sec memory limit 1280 mb submit 1960 solved 484 submit status discuss 描述zcwwzdjn在追殺十分sb的zhx,而zhx逃入了乙個遙遠的國度。當zcwwzdjn準備進入遙遠的國度繼續追殺時,守護神ra...