NOIP2016 天天愛跑步 題解

2022-06-20 14:21:11 字數 1855 閱讀 6653

題目鏈結

首先,把每條路徑拆成如下兩條路徑。

從起點到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 天天愛跑步 不帶修改的樹上路徑資訊的維護,很容易想到樹上差分。我們考慮一條路...