bob 有一棵 \(n\) 個點的有根樹,其中 \(1\) 號點是根節點。bob 在每個點上塗了顏色,並且每個點上的顏色不同。
定義一條路徑的權值是:這條路徑上的點(包括起點和終點)共有多少種不同的顏色。
bob 可能會進行這幾種操作:
bob 一共會進行 \(m\) 次操作。
\(1\leq n \leq 10^5\),\(1\leq m \leq 10^5\)。
發現每次修改都是直接把 \(x\) 到根的路徑的顏色全部賦值,然後原來的顏色就失效了,容易發現任意時刻每乙個節點最多有乙個兒子的顏色與其相同。
發現這個操作和 lct 的 access 十分相似,每乙個點只可以保留一條實邊。
如果我們把操作一看做將 access(\(x\)),那麼乙個點的權值就轉換為了該點到根節點的虛邊的數量。
在 access 的時候,當我們把 \(x\) 與其原來的實兒子的邊斷開時,它實兒子所在子樹的權值全部加 \(1\),連線新的實兒子 \(y\) 後,\(y\) 所在子樹內的權值全部減 \(1\)。
那麼用乙個線段樹維護區間和以及區間最大值即可。注意是乙個節點所在子樹內的權值加減,所以要先 findrt,然後在找到的根節點進行修改。但是 findrt 之後不能 splay,否則會改變 splay 的形態。
然後對於操作 \(2\),答案即為 \(x,y\) 的權值和減去他們 lca 的權值的兩倍再加上 \(1\)。操作三直接區間最大值即可。
時間複雜度 \(o(m\log^2n)\)。
#include using namespace std;
const int n=100010,lg=18;
int n,m,tot,head[n],dfn[n],rk[n],siz[n],dep[n],f[n][lg+1];
struct edge
e[n*2];
void add(int from,int to)
; head[from]=tot;
}struct segtree }
void pushup(int x)
void build(int x,int l,int r)
int mid=(l+r)>>1;
build(x*2,l,mid); build(x*2+1,mid+1,r);
pushup(x); }
void update(int x,int l,int r,int ql,int qr,int v)
pushdown(x);
int mid=(l+r)>>1;
if (ql<=mid) update(x*2,l,mid,ql,qr,v);
if (qr>mid) update(x*2+1,mid+1,r,ql,qr,v);
pushup(x); }
int query(int x,int l,int r,int ql,int qr)
}seg;
struct lct
bool notrt(int x)
void rotate(int x)
void splay(int x) }
int findrt(int x)
void access(int x)
if (y)
ch[x][1]=y;
} }}lct;
void dfs(int x,int fa) }}
int lca(int x,int y)
int main()
tot=0; dfs(1,0);
seg.build(1,1,n);
while (m--)
if (opt==2)
if (opt==3)
}return 0;
}
P3703 SDOI2017 樹點塗色
鏈結分析 首先對於詢問,感覺是線段樹維護dfs序,每個點記錄到根的顏色個數。第二問差分,第三問區間取max。那麼考慮修改,每次將乙個點的顏色變成和父節點的顏色一樣的過程中,這個點的子樹內都會 1。這個修改的過程我們可以認為是修改邊的過程,將一些邊設為1,一些邊設為0,那麼一次修改對於乙個點就是將原來...
洛谷P1283 平板塗色(dfs)
ce數碼公司開發了一種名為自動塗色機 apm 的產品。它能用預定的顏色給一塊由不同尺寸且互不覆蓋的矩形構成的平板塗色。為了塗色,apm需要使用一組刷子。每個刷子塗一種不同的顏色c。apm拿起一把有顏色c的刷子,並給所有顏色為c且符合下面限制的矩形塗色 為了避免顏料滲漏使顏色混合,乙個矩形只能在所有緊...
洛谷P4170 CQOI2007 塗色
假設你有一條長度為5的木版,初始時沒有塗過任何顏色。你希望把它的5個單位長度分別塗上紅 綠 藍 綠 紅色,用乙個長度為5的字串表示這個目標 rgbgr。每次你可以把一段連續的木版塗成乙個給定的顏色,後塗的顏色覆蓋先塗的顏色。例如第一次把木版塗成rrrrr,第二次塗成rgggr,第三次塗成rgbgr,...