SDOI2017 樹點塗色(LCT 線段樹)

2022-06-16 03:30:10 字數 2727 閱讀 9253

給你一棵以\(1\)為根,有\(n\)個節點的樹,初始時每個節點的顏色互不相同,記一條路徑的權值為這條路徑(包括起點和終點)上所有不同的顏色個數,一共\(m\)個操作,每次支援以下\(3\)種操作之一:

把點\(x\)到根節點的路徑上所有的點染上一種沒有用過的新顏色

求\(x\)到\(y\)的路徑的權值

在以\(x\)為根的子樹中選擇乙個點,使得這個點到根節點的路徑權值最大,求最大權值

\(n \leq 10^\), \(m \leq 10^\)

可以發現,這道題目根節點是固定的,同一種顏色一定是樹上深度從小到大連續的一段

記\(v_\)表示\(x\)到根節點的路徑權值

則第\(2\)個操作中求的權值為\(v_+v_-v_+1\)

方法一:重鏈剖分+線段樹維護\(v_\)

但是由於我最近在做\(lct\)專題,所以這邊的做法是和\(lct\)有關

方法二:\(lct\)維護樹上染色連通塊+線段樹維護\(v_\)

通過這道題,我才知道\(lct\)維護樹上染色連通塊是什麼意思其實就是直接維護,這道題加深了我對\(access\)的理解

我們可以另\(lct\)上每個\(splay\)表示一種染色連通塊,這個\(splay\)上的點顏色都相同,且與這個顏色相同的點都在這個\(splay\)上

\(access(x)\)操作就是把根節點到\(x\)這條鏈染為同一種顏色,放在乙個\(splay\)中,又由於\(lct\)操作是不會影響到這條鏈以外其他點之間的連通性的,把這條鏈提出來後,其他點該在哪個\(splay\)還是在哪個\(splay\)

然後如下,\(access\)裡面把\(x\)與\(son[x][1]\)之間的實邊斷開,再連虛邊,它會對在原樹上\(x\)在\(son[x][1]\)方向的子樹產生影響,要找的是與\(x\)相連的點,而不是\(son[x][1]\),所以還要乙個\(find_root(son[x][1])\)找\(son[x][1]\)所在\(splay\)的根,而虛邊轉實邊也差不多

inline void access(int x)

if (u)

son[x][1] = i;

}}

由於\(lct\)的複雜度是\(\theta(log\ n)\)的,線段樹修改的時間複雜度也是\(\theta(log\ n)\)的,所以總的期望複雜度是\(\theta(nlog^ n)\)的

#includeusing namespace std;

#define re register int

const int n = 100005;

int n, m, cnt, tim, dep[n], dfn[n], lst[n], g[n], hea[n], nxt[n << 1], to[n << 1], f[n][18], maxn[n << 2], lz[n << 2], fa[n], son[n][2];

inline int read()

inline void write(int x)

int num = 0;

char sc[10];

while (x) sc[++num] = x % 10 + 48, x /= 10;

while (num) putchar(sc[num--]);

putchar('\n');

}inline void add(int x, int y)

inline void dfs(int x)

lst[x] = tim;

}inline int lca(int x, int y)

inline void bui(int id, int l, int r)

int mid = l + r >> 1;

bui(id << 1, l, mid), bui(id << 1 | 1, mid + 1, r);

maxn[id] = max(maxn[id << 1], maxn[id << 1 | 1]);

}inline void push_down(int id)

inline void modfy(int id, int l, int r, int x, int y, int z)

if (lz[id]) push_down(id);

int mid = l + r >> 1;

if (x <= mid) modfy(id << 1, l, mid, x, y, z);

if (y > mid) modfy(id << 1 | 1, mid + 1, r, x, y, z);

maxn[id] = max(maxn[id << 1], maxn[id << 1 | 1]);

}inline int que(int id, int l, int r, int x, int y)

inline bool check(int x)

inline void rotate(int x)

inline void splay(int x)

}inline int find_root(int x)

inline void access(int x)

if (u)

son[x][1] = i; }}

int main()

dfs(1);

bui(1, 1, n);

while (m--)

else write(que(1, 1, n, dfn[u], lst[u]) + 1);

} return 0;

}

Sdoi2017 樹點塗色 lct 線段樹

題意 一棵有根樹,支援x到根染成新顏色,求x到y顏色數,求x子樹裡點到根顏色數最大值 考場發現這個資訊是可減的,但是沒想到lct 特意設計成lct的形式!如何求顏色數?維護乙個點和父親的顏色是否一樣,不一樣為1,就是字首和。考慮相鄰的思想和那道 水位線 有點像 x到y的答案就是 s x s y 2 ...

SDOI2017 樹點塗色 LCT 線段樹

可以發現更新操作就是 text 的 text 操作,這個操作複雜度是 o n log n 的 因此,考慮對於每次的 text 操作,維護每個點到根的路徑上不同的權值個數 每次 text 操作只設計到合併兩個鏈 斷開一條鏈兩種操作,可以通過線段樹維護子樹修改 那麼修改的複雜度就是 o n log 2 ...

SDOI2017 樹點塗色

description bob有一棵n個點的有根樹,其中1號點是根節點。bob在每個點上塗了顏色,並且每個點上的顏色不同。定義一條路 徑的權值是 這條路徑上的點 包括起點和終點 共有多少種不同的顏色。bob可能會進行這幾種操作 1 x 把點x到根節點的路徑上所有的點染上一種沒有用過的新顏色。2 x ...