洛谷 P1600 天天愛跑步(LCA 亂搞)

2022-02-28 03:27:58 字數 2377 閱讀 6491

傳送門

我們把每一條路徑拆成$u->lca$和$lca->v$的路徑

先考慮$u->lca$,如果這條路徑會對路徑上的某乙個點產生貢獻,那麼滿足$dep[u]-dep[x]=w[x],dep[u]=dep[x]+w[x]$,注意到$dep[x]+w[x]$是乙個定值,所以我們只要去找它的子樹裡有多少個點的$dep$等於$dep[x]+w[x]$就可以了,這個可以直接開乙個桶。然而如果點$x$在$lca$的上面,這一條路徑是不會對他產生貢獻的,那麼我們就得在$lca$處把這一條路徑的貢獻給減去。具體怎麼做呢?我們可以利用樹上差分的思想,在點$u$把它的出現次數$+1$,在$lca$處把它的出現次數$-1$,那麼我們對於每乙個點,只要去查詢它的子樹裡$dep[x]+w[x]$這個值出現了多少次就可以了。

順便注意一下,因為我們的桶裡存的不止是一棵子樹的答案,所以查詢得到的次數可能是來子其他子樹的。那麼我們可以dfs進去之前先記錄一下,完了之後再記錄一下,兩次的差就是這個值在其子樹里的實際出現次數

然後$lca->v$的路徑咋搞嘞?只要把式子改成$dep[v]-dep[x]=len-w[i]$($len$表示路徑長度),然後和上面一樣的做法。注意這裡有可能會出現負數,所以我們要讓它加上$3e5$

注意到$lca$會被我們統計兩次,那麼我們只要最後做完之後,把所有被統計了兩次答案的$lca$答案減一就好了

1

//minamoto

2 #include3 #include4 #include5 #include6

using

namespace

std;

7#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?eof:*p1++)

8char buf[1

<<21],*p1=buf,*p2=buf;

9 templateinline bool cmax(t&a,const t&b)

10 inline int

read()

20char sr[1

<<21],z[20];int c=-1

,z;21 inline void ot()

22 inline void print(int

x)27

const

int n=300005,m=600005;28

inthead[n],next[m],ver[m],tot;

29int

son[n],sz[n],fa[n],dep[n],top[n];

30int c[n],w[n],val[n],num[1000005

];31

intn,m,lim,ans[n];

32 vectorqaq[n],qaq2[n],qaq3[n];

33struct nodeq[n];

34 inline void add(int u,int

v)38

void dfs1(int

u)46}47

}48void dfs2(int u,int

t)55

}56 inline int lca(int u,int

v)60

return dep[u]u:v;61}

62void dfs(int u,int

fa)67 c[dep[u]]+=val[u];if(now<=lim) ans[u]=c[now]-k;

68for(int i=0,s=qaq[u].size();ic[dep[qaq[u][i]]];69}

70void dfs(int u,int

fa)75

for(int i=0,s=qaq2[u].size();i300000+qaq2[u][i]];

76 ans[u]+=num[now]-k;

77for(int i=0,s=qaq3[u].size();i300000+qaq3[u][i]];78}

79int

main()

85for(int i=1;i<=n;++i) w[i]=read();

86 dfs1(1),dfs2(1,1

);87

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

92 dfs(1,0

);93

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

97 dfs(1,0

);98

for(int i=1;i<=m;++i) if(dep[q[i].s]-dep[q[i].lca]==w[q[i].lca]) --ans[q[i].lca];

99for(int i=1;i<=n;++i) print(ans[i]);

100ot();

101return0;

102 }

洛谷 P1600 天天愛跑步

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

洛谷P1600 天天愛跑步

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

洛谷P1600 天天愛跑步 差分 LCA 桶

題目鏈結 一步一步的來考慮 25 直接 o nm 的暴力 鏈的情況 維護兩個差分陣列,分別表示從左向右和從右向左的貢獻,s i 1 統計每個點的子樹內有多少起點即可 t i 1 同樣還是差分的思想,由於每個點 能對其產生的點的深度是相同的 假設為 x 那麼訪問該點時記錄下 dep x 的數量,將結束...