洛谷1600 天天愛跑步(樹鏈剖分)

2021-08-29 20:53:51 字數 1496 閱讀 2437

哇這真的是day1t2嗎。。。。。感覺要被強行勸退了。。。。。qwq

首先對於樹上的路徑s->t,我們都可以將其拆為s->lca(s,t)->t,我們用dona陣列作為記錄貢獻的桶。

考慮乙個點i能被觀察到的情況,分為兩種:

1.存在一條路徑s->lca(s,t),且depth[i]+val[i](即原題的w)=depth[s]

2.存在一條路徑lca(s,t)->t,且depth[i]-val[i]=depth[t]-lenth[s,t](lenth陣列記錄s->t的路徑長度)

所以我們考慮記錄兩個貢獻:乙個點在s->lca(s,t)上的貢獻和lca(s,t)->t上的貢獻,在dfs的時候我們記錄dfs前和dfs後的差值,就是最後該點的貢獻。(在**中用1~maxn維護第乙個,maxn+1~maxn*2維護第二個)

對於樹上的節點,維護三個資訊:以該點為終點的路徑編號,以該點為lca的路徑的編號,以該點為起點的次數,用前兩者統計對祖先的貢獻,後者統計不會做出貢獻的點,注意有可能lca會被重複計算,所以要在處理路徑資訊的時候提前減去。

反正寫的很難受qwq,noip好難好難qwq

#includeusing namespace std;

const int maxn=6e5+10;

const int maxm=1e6+21000;

int n,m,cnt,s[maxn],t[maxn],lc[maxn],lenth[maxn];

int head[maxn],depth[maxn],fa[maxn],son[maxn],siz[maxn],top[maxn],val[maxn],c[maxn];

int nxt[maxm],to[maxm];

int start[maxn],dona[maxm<<1],a[maxn],len[maxn],ans[maxn];

vectoranc[maxn],end[maxn];

int read()

void add(int x,int y)

void dfs1(int u,int fat) }}

void dfs2(int u,int tp) }}

int lca(int x,int y)

return depth[x]}void dfs3(int u)

dona[depth[u]]+=start[u];

for(int i=0;ians[u]+=dona[depth[u]+val[u]]-xx+dona[val[u]-depth[u]+maxn]-yy;

for(int i=0;ireturn;

}int main()

for(int i=1;i<=n;++i)

val[i]=read();

dfs1(1,0);

dfs2(1,1);

for(int i=1;i<=m;++i)

dfs3(1);

for(int i=1;i<=n;++i)

cout

}

洛谷 P1600 天天愛跑步

題面就不貼上了 把每個玩家的路徑拆成一條到lca的路徑和從lca到終點的路徑 然後,使用樹上差分統計答案即可 那麼,樹上差分是什麼?差分的具體思想是,當某區間內某元素對答案有貢獻,就在區間起點打乙個 1 標記代表多出了乙個對答案有貢獻的元素,在終點打乙個 1標記代表乙個對答案有貢獻的元素在該位置 結...

洛谷P1600 天天愛跑步

樹上的題有點意思啊 這題我最開始的想法是 固定乙個觀測點i,能觀測到的一定是起點距離 i 為 w i 的點的子集合。問題是這個集合只有一部分的點會經過 i 點,就很煩。於是得換個思路,不放固定乙個跑步的人 x 觀察他對哪些觀察者 i 產生了貢獻。於是我們得到了公式,對於上公升階段的點來說,不妨設 s...

洛谷 差分 LCA P1600 天天愛跑步

題目傳送門 考慮如果直接模擬每個人的路徑複雜度就會達到o n m o nm o nm 級別,這樣做肯定要 於是換個方向思考 我們以觀察員的視角來解決這道題。即我們統計每個人對於每個觀察員的貢獻。對於第i ii個人的行動,我們可以分成兩部分來看 記u uu是s,t s,ts,t的最近公共祖先,d u ...