BZOJ 3083 遙遠的國度 樹鏈剖分 LCA

2022-05-05 20:45:08 字數 4431 閱讀 1875

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 7

1 2

1 3

1 2 3

1

3 1

2 1 1 6

3 1

2 2 2 5

3 1

2 3 3 4

3 1

sample output

1

2

3

4

提示

對於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。

題解:首先看到路徑修改和子樹查詢,樹鏈剖分就沒得跑了,當然也可以寫lct

操作2/3用樹剖自然好寫,難的是一,換根怎麼看怎麼尬

想了一想,如果根就是詢問點,子樹就是整個區間

如果根在祖先,該點的子樹不變.仍是按照正規的樹剖查法查

如果根在詢問點的任何乙個子樹中,那麼該詢問點的子樹就變成了除了這個子樹之外的所有區間.

主要是如何確定這個根在哪個子樹中比較麻煩,寫乙個類似lca的玩意,倍增記錄他的祖先,到時候一點點跳上去,複雜度還是可以接受的.

我一直以為是線段樹寫錯了,果然做題太少了orz

**如下:

#include#include

#include

#include

#include

#define lson root<<1

#define rson root<<1|1

#define inf 0x3f3f3f3f

using

namespace

std;

struct

node

tr[400040

];int n,deep[100010],son[100010],fa[100010],size[100010],id[100010],top[100010],c[100010],w[100010

],cnt,rt;

vector

g[100010

];void push_up(int

root)

void push_down(int

root)

void build(int root,int l,int

r)

int mid=(l+r)>>1

; tr[root].l=l;

tr[root].r=r;

tr[root].lazy=inf;

build(lson,l,mid);

build(rson,mid+1

,r);

push_up(root);

}void update(int root,int l,int r,int

val)

int mid=(tr[root].l+tr[root].r)>>1

;

if(tr[root].lazy!=inf)

if(l>mid)

else

else

}push_up(root);

}int query(int root,int l,int

r)

if(tr[root].l==l&&tr[root].r==r)

int mid=(tr[root].l+tr[root].r)>>1

;

if(tr[root].lazy!=inf)

if(l>mid)

else

}return min(query(lson,l,mid),query(rson,mid+1

,r));

}void dfs1(int now,int f,int

dep)

dfs1(g[now][i],now,dep+1

); size[now]+=size[g[now][i]];

if(size[g[now][i]]>maxson)

}}void dfs2(int now,int

topf)

dfs2(son[now],topf);

for(int i=0; i)

dfs2(g[now][i],g[now][i]);

}}void path_update(int x,int y,int

val)

update(

1,id[top[x]],id[x],val);

x=fa[top[x]];

}if(deep[x]>deep[y])

update(

1,id[x],id[y],val);

}int sub_query(int

x)

if(id[rt]<=id[x]+size[x]-1&&id[rt]>=id[x])

return query(1,id[x],id[x]+size[x]-1);}

intmain()

for(int i=1;i<=n;i++)

scanf("%d

",&rt);

dfs1(rt,

0,1);

dfs2(rt,rt);

build(

1,1,n);

intkd,ll,rr,vv;

for(int i=1;i<=m;i++)

if(kd==2

)

if(kd==3

)

}}

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...