首先,我們考慮對於一條路徑
從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 我們用桶標記 ...