天天愛跑步NOIP

2021-08-06 05:21:36 字數 1800 閱讀 1741

首先,我們考慮對於一條路徑

從x->y,可以把它拆分成兩部分,圖中用虛線分開,然後這條路徑就變成了x->lca,son[lca]->y

先來考慮從x向上走到lca的路徑,對於這條路上的節點i,玩家能對節點i產生貢獻的前提是deep[x]-w[i]=deep[i]

移項可得deep[x]=w[i]+deep[i],也就是說起點在w[i]+deep[i]這個深度的玩家向上走的時候都會對節點i產生1的貢獻,(玩家想對節點i產生貢獻,那它的深度一定等於w[i]+deep[i])

對於每一層深度建一顆線段樹,動態開點,先dfs整個樹,求出每個節點的dfs序,那麼這就轉化成區間問題,對於每乙個玩家s->t,在深度為deep[s]的線段樹id[s]的位置加1,id[fa[lca(s,t)]]-1,利用了差分思想,每一次求一下節點i在深度為w[i]+deep[i]的線段樹里[in[i],out[i]]區間和就是答案,利用差分可以防止不合法的計算,id[fa[lca(s,t)]]-1,保證x不會被lca以上的節點計算貢獻

然後考慮向下的路徑,對於son[lca]->y的路徑上的節點j,玩家能對j產生貢獻前提是deep[x]+deep[y]-2*deep[lca(x,y)]-w[j]=deep[y]-deep[j]

移項可得deep[x]-2*deep[lca(x,y)]=w[j]-deep[j]相應的,我們在deep[x]-2*deep[lca]深度的線段樹id[x]的位置加1,lca處減1,然後對於每個節點,查詢w[j]-deep[j]深度的線段樹[in[j],out[j]]即可

注意紅字部分可能出現負數,下標統一加n

#include#include#include#include#define maxn 300005

using namespace std;

int n,m;

int fa[maxn],d[maxn*5],ans[maxn];

struct edge

b[maxn*2];

int kk=0,head[maxn];

struct edge2

s[maxn*2];

int w[maxn];

int f[maxn][35];

inline int read()

return x;

}inline void add(int u,int v)

inline void init()

void pre()

return fa[x];

}int q[maxn],h[maxn],id=0;

void dfs(int x)

h[x]=id;

}int root[maxn*30],sum[maxn*30],ls[maxn*30],rs[maxn*30];

int cnt=0;

struct tree

void insert(int &k,int l,int r,int x,int w)

int quiry(int k,int l,int r,int ll,int rr)

}tr;

inline void init2()

int main()

{ freopen("runninga.in","r",stdin);

freopen("runninga.out","w",stdout);

init();

n=read();m=read();

int x,y,anc;

for(int i=1;i

跑步愛天天

對於 50 的資料 直接模擬 對於另外10 的資料 因為地圖是一條鏈,顯然 yousiki 會消滅所有距離他為偶數條邊的祖 先。對於100 的資料 我們先把整個樹 dfs 一遍,遇到乙個點就把這個點記錄到乙個陣列後邊,即求出了樹的尤拉序,顯然如果不考慮迴圈的話,guard是在這個序列上每次往後走乙個...

天天愛跑步

一道 樹上差分 lca 桶的題 說實話,這道題放在d1t2就是非常不合理的。然而ccf就是放了,並且還是能依靠csp撈錢,你也必須交錢參加比賽。這個社會是多麼的不公啊!閒扯結束 顯然如果對每條路徑都進行一次處理,複雜度不對。考慮對路徑進行一次預處理,然後進行統一的計算答案。我們發現當一條路徑對某乙個...

天天愛跑步

終於拿下noip最難一題 看別人的題解看不懂 於是準備寫一篇更通俗易懂雜亂無章的題解 樹上差分 線段樹 桶 lca 將每條路徑在lca處切成上公升路徑和下降路徑 會發現對於x號觀察員若觀察到玩家i 則必有dep i w x depx 或dep i 2 dep lca w x depx 我們用桶標記 ...