GDOI2017 取石子遊戲 LCA

2022-03-29 04:37:53 字數 1657 閱讀 4102

給出一棵樹,每個點都有乙個權值。對於每個節點,求去掉該節點的子樹後,剩下所有節點的權值mex(最小的沒有出現的非負整數。)

用權值線段樹合併亂搞顯然是可行的,但細節很多且需要卡常。

我們考慮所有權值為\(i\)的節點對答案的影響。求所有節點的lca,那麼對於從lca向上到根的路徑上的節點,去掉子樹後的部分中一定沒有值\(i\).那麼值\(i\)就可能成為它們的mex。

因此按權值從小到大,每次求出權值為\(i\)的節點的lca,然後暴力往上跳,把沒有被更新過的節點的答案設為\(i\),否則已經更新過的節點答案一定比\(i\)小,可以停止。當找到第乙個沒有節點出現的權值時,這個權值可以用來更新整棵樹的mex,直接掃一遍更新答案即可。

容易發現更新答案的複雜度是\(o(n)\)的,再加上求lca,複雜度\(o(n \log n)\)

#include#include#include#include#define maxn 1000000

using namespace std;

templatevoid qread(t &x)

while(c>='0'&&c<='9')

x=x*sign;

}templatevoid qprint(t x) else if(x==0) else

}int cas,n,m;

struct edge e[maxn*2+5];

int esz=1;

int head[maxn+5];

void add_edge(int u,int v)

int a[maxn+5];

vectorpos[maxn+5];

int ans[maxn+5];

int fa[maxn+5],son[maxn+5],sz[maxn+5],top[maxn+5],deep[maxn+5];

void dfs1(int x,int f) }}

void dfs2(int x,int t) }}

int lca(int x,int y)

if(deep[x]else return y;

}void clear()

int main()

cerr<<"ok"

for(int i=1; i<=n; i++) ans[i]=-1;

for(int i=1; i<=n; i++) pos[a[i]].push_back(i);

cerr<<"ok"

dfs2(1,1);

cerr<<"ok"

int lc=0;

for(int j=0; j<(int)pos[i].size(); j++)

//除了lc子樹外,剩下的部分都沒有值i

for(int x=lc; x&&ans[x]==-1; x=fa[x]) ans[x]=i; //更新mex

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

putchar('\n');

}// system("pause");}/*

16 5

5 2 1 0 3 1

1 21 3

1 43 5

2 6*/

GDOI2017模擬8 12 躲藏

給出乙個n m的網格圖,圖中有一些障礙節點。現在有a個男生和b個女生,還有乙個小標。男生要和女生配對,小標可以和任何乙個人配對。每一對cp 霧 只能待在乙個點。乙個點只能有一對cp。現在給出a b 1個人的初始座標,和他們的移動速度 即移動到4相鄰格仔所需的時間 所有人同時移動,求完成配對的最小時間...

GDOI2017模擬8 12 新車

平面上有乙個數軸,e點為目標點。你現在要開 車從w前往e,每移動1格需要1l油。你的油箱容量為s,初始時裝滿了98 汽油。數軸上有n個加油站,每個加油站提供98 95 92 中的一種。到了加油站你可以選擇加任意數量的油,你的油箱是茲瓷所有油甚至混合油的。你認為98 最吼,95 其次,92 跑的最慢。...

GDOI2017模擬11 5 總結

看到第一題,哇,數論題,不會啊,感覺要跪 正當我迷茫的時候,突然機房斷電了。啪的一聲大家的電腦都黑了!不知所措!沒辦法,只好等等。過了10分鐘左右,來電了,重新看了看第一題,也許是冷靜下來了,發現直接暴力分解質因數就能過!繼續看第二題,在草稿紙上推了一下,要用揹包,一開始以為會超時,但仔細想了想發現...