題目鏈結
首先,把每條路徑拆成如下兩條路徑。
從起點到lca的路徑。
從lca到終點的路徑。
對這兩條路徑分別處理。
首先,處理從起點到lca的路徑。
為了方便,我們把這條路徑拆成兩條,進行差分:
用從起點到根的路徑,減去從lca到根的路徑,得出這條路徑的貢獻。
現在我們要處理如下路徑:
從x點出發,走到根,出發時間為t,貢獻為g(1或-1)。
這個操作對點u有貢獻,當且僅當滿足如下條件:(設sd[x]為x的深度,w[u]表示結點u出現觀察員的時間)
x在u的子樹中。
t[x]+(sd[x]-sd[u])=w[u] (即sd[u]+w[u]=sd[x]+t[x])。
所以,開乙個陣列記錄sd[u]+w[u]的出現次數,dfs到u時,用dfs(u)之後的結果-之前的結果,就是u的子樹中的x的貢獻。(dfs之後比dfs之前僅多包含了u的子樹)。
然後,處理從lca到終點的路徑。
同樣,拆成兩條,進行差分。
我們設從終點為x,起點為根,出發時間為t,貢獻為g(1或-1)。
這個操作對點u有貢獻,當且僅當滿足如下條件:(設sd[x]為x的深度,w[u]表示結點u出現觀察員的時間)
x在u的子樹中。
w[u]=sd[u]+t[x] (即w[u]-sd[u]=t[x])。
同樣,開乙個陣列記錄w[u]-sd[u]的出現次數,然後用同樣的方法dfs處理。(這裡下標有負數,可以通過同時加乙個值來解決)。
**:
#include #include int fr[300010],ne[600010];
int v[600010],bs=0,mi=0;
int shu[300010],son[300010];
int sd[300010],top[300010];
int fa[300010],w[300010];
int sl1[1500010],sl2[1500010];
int sl3[1500010],sl4[1500010];
int jg[300010],lc[300010];
struct slb
void addlb(int a,int b)
shu[u]+=shu[t];
} }}void dfs2(int u,int f,int tp)
}int lca(int x,int y)
return sd[x]}void dfs3(int u,int f)
j=(yq<0?0:sl1[yq])-j;
jg[u]+=j;
}void dfs4(int u,int f)
j=(yq<0?0:sl2[yq])-j;
jg[u]+=j;
}void dfs5(int u,int f)
j=(yq<0?0:sl3[yq])-j;
jg[u]-=j;
}void dfs6(int u,int f)
j=(yq<0?0:sl4[yq])-j;
jg[u]-=j;
}int main()
dfs1(1,-1);
dfs2(1,-1,1);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=0;imi=-mi;
dfs3(1,-1);
dfs4(1,-1);
dfs5(1,-1);
dfs6(1,-1);
for(int i=1;i<=n;i++)
printf("%d ",jg[i]);
return 0;
}
NOIP2016 天天愛跑步
時間限制 2 s 記憶體限制 512 mb 題目描述 小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一棵包含n個結點和n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。...
NOIP2016天天愛跑步
小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一一棵包含 nn n個結點和 n 1n 1n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從11 1到nn...
NOIP2016 天天愛跑步
看這道題不爽很久了,但一直沒有開它,原因是我不會 我太菜了 看了題解還是寫不來,因為我不會線段樹合併。然後今天學了dsu on tree這種神奇的科技,成功把它a了,效率吊打線段樹合併。於是寫篇題解紀念一下。洛谷p1600 天天愛跑步 不帶修改的樹上路徑資訊的維護,很容易想到樹上差分。我們考慮一條路...