[CF600E] Lomsat Gelral [樹鏈剖分]
阿新 • • 發佈:2018-12-12
題意: 給出一個有個點,以號點為根的有根樹。每個點有一種顏色。 以某個點為根的子樹中,如果一種顏色出現的次數不比其它顏色少,稱它是這個點的支配顏色。 點的支配顏色的和,是指,某個點的所有支配顏色的編號的和。 求這棵樹上每個點的支配顏色的和。
簡單地考慮:
可以暴力統計每個點,每種顏色的出現次數。
這種做法顯然會爆炸,也顯然有很大的優化空間。
我們知道到某個點的等於它的所有兒子的的和,所以兒子的資訊不能白白浪費。
,然後返回的時候把子樹的貢獻加到父親上? 雖然好像少了刪除的步驟,但是實際上, 不僅爆了空間(存每個點的答案一共),也爆了時間(掃一遍加貢獻一共)。
既然沒法完全儲存兒子的資訊,再加上只能儲存級別的資訊(每個顏色出現次數)
那麼頂多就把一個兒子的資訊帶上來,其它兒子只能暴力了。顯然帶上重兒子最優。
這樣能夠減少多少開銷?
。訪問某一個點的時候, 我們先把它的輕兒子都逐個遞迴下去,然後再解決重兒子。 統計完一個輕兒子要把它的資訊拋棄掉,再統計下一個 而統計完重兒子,這個點的所有兒子也都有答案了。 可以留下重兒子的資訊,再暴力加上輕兒子的資訊和正在訪問的點本身的資訊,得出這個點的答案。
怎麼分析複雜度?很明顯我們需要知道的就是某一個點會被暴力統計多少次
已經有了輕重兒子的概念了,乾脆按照樹鏈剖分的思路來分析 輕邊有, 並且由此可得一條從根向下的路徑經過的輕邊不會超過條, 經過重鏈數量也不會超過輕邊數量。
某個點到根的路徑上有多少條輕邊,這個點就會被統計幾次。
複雜度是。
也可以搞樹上啟發式合併,每次把小的合併進大的裡面。
暴力統計可以在序上也可以直接在樹上暴力統計,隨意了
注意可能爆
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<cctype>
using namespace std;
#define LL long long
#define add_edge(a,b) nxt[++tot]=head[a],head[a]=tot,to[tot]=b
int N,tot=0,mx=0;
LL tmp=0;
int ci[100005]={},nxt[200005]={},head[200005]={},to[200005]={};
int siz[100005]={},son[100005]={};
int cnt[100005]={};
LL ans[100005]={};
bool vis[100005]={};
void pthDec(int x,int fa)
{
siz[x]=1;
for(int t=1,i=head[x];i;i=nxt[i])
{
if(to[i]==fa)continue;
pthDec(to[i],x); siz[x]+=siz[to[i]];
if(siz[to[i]]>t)t=siz[to[i]],son[x]=to[i];
}
}
void modify(int x,int fa,int delta)
{
cnt[ci[x]]+=delta;
if((delta==1)&&(cnt[ci[x]]>=mx))
{
if(cnt[ci[x]]>mx)tmp=0,mx=cnt[ci[x]];
tmp+=ci[x];
}
for(int i=head[x];i;i=nxt[i])
{
if((to[i]==fa)||vis[to[i]])continue;
modify(to[i],x,delta);
}
}
void dfs(int x,int fa,bool keep)
{
for(int i=head[x];i;i=nxt[i])
{
if(to[i]==fa||to[i]==son[x])continue;
dfs(to[i],x,0);
}
if(son[x])dfs(son[x],x,1),vis[son[x]]=1;
modify(x,fa,1),ans[x]=tmp;
if(son[x])vis[son[x]]=0;
if(!keep)modify(x,fa,-1),mx=tmp=0;
}
int main()
{
scanf("%d",&N);
for(int i=1;i<=N;++i)scanf("%d",&ci[i]);
for(int u,v,i=1;i<N;++i)
{
scanf("%d%d",&u,&v);
add_edge(u,v); add_edge(v,u);
}
pthDec(1,0);
dfs(1,0,0);
for(int i=1;i<=N;++i)printf("%I64d ",ans[i]);
return 0;
}