豪哥生活在乙個n個點的樹形城市裡面,每一天都要走來走去。雖然走的是比較的多,但是豪哥在這個城市裡面的朋友並不是很多。
當某一天,猴哥給他展現了一下大佬風範之後,豪哥決定要獲得一些交往機會來提公升交往能力。豪哥現在已經物色上了一條友,打算和它(豪哥並不讓吃瓜群眾知道性別)交往。豪哥現在spy了一下這個人的所有行程起點和終點,豪哥打算從終點開始走到起點與其相遇。但是豪哥是想找話題的,他想知道以前有多少次行程和此次行程是有交集的,這樣豪哥就可以搭上話了。這個路徑與之前路徑的有交集數量作為豪哥此次的交往機會。
但是豪哥急著要做交往準備,所以算什麼交往機會的小事情就交給你了。
第一行乙個正整數n表示節點個數。接下來n-1行,每行兩個正整數分別是u,v表示節點u和v之間有連邊。接下來一行乙個 正整數m表示路徑個數。然後有m行,每行兩個正整數分別是u,v分別表示u到v之間有一條路徑。
輸出共m行,每行乙個整數,第i行表示豪哥在這條路徑上獲得的交往機會。
51 2
1 33 4
3 54
4 54 2
1 31 201
22對於20%的資料n,m≤2000
對於另外20%的資料n,m≤50000
對於另外10%的資料n,m≤200000保證樹形結構是一條鏈
對於另外50%的資料n,m≤200000
(口胡開始)
我們先找一下對於兩條路徑(a,b)和(c,d),如果他們有交集有什麼規律?
不難發現,如果兩條路徑有交集,那麼對於lca(a,b)和lca(c,d),要麼lca(a,b)在路徑(c,d)上,要麼lca(c,d)在(a,b)上,要麼兩個lca相同,證明就一句話,感性理解:假設我們現在手上是一條 lca 深度大的路徑,這條路徑最高可達點就是 lca,若 lca不在另一條路徑上,又因為他lca深度大,所以不可能在另外一條路徑 lca上方,所以就沒有可達點了。
所以這個問題就轉化為兩個問題:1.當前路徑上有幾個之前的lca;2.之前路徑有幾個經過當前路徑的lca;(當然要特判一下lca相同的時候)
1.當前路徑上找lca
因為這是一顆靜態樹,所以考慮用dfs序來解決。對於乙個點x,a->lca(a,b)這樣的樹鏈如果經過他,則一定是從它的子樹走向它的祖先。 然後就比較顯然了,每多加乙個這樣的x,則給他子樹中所有點的權值都+1. 查詢(a,lca(a,b),b)的時候,就用 a權+b權-lca權*2. 若 a與lca在x的上下兩方,則會被累加到貢獻。若同時在x的下方,則會被 lca權減掉。
2.在之前路徑上找lca
同樣地考慮dfs序, 很方便的樹上字首和。若有一條路徑(a,b),則給lca(a,b) +1,a-1,b-1.然後查詢乙個點到根的權值和,這是離線時的套路。 但這題這樣不好做,因為不能每一次都重構樹,於是我們變一下,變成類似樹上字尾和的東西。
對於一條路徑(a,b),給a+1,b+1,lca-2. 乙個點的子樹權值和就是他的權值。
用兩樹狀陣列維護一下dfs 序上的資訊,我們就把這道題給搞定了。
這題的坑點主要在於,兩個樹狀陣列維護的資訊意義是不一樣的,壓根不可以相提並論。
#includeusing namespace std;
const int maxn=2e5+10;
#define lowbit(x) ((x)&(-x))
#define treesum(t,x) (sum(t,r[x])-sum(t,l[x]-1))
int n,m,stm,cnt;
int head[maxn],depth[maxn];
int l[maxn],r[maxn];
int to[maxn<<1],nxt[maxn<<1];
int f[maxn][19];
int t1[maxn],t2[maxn],ans;
void change(int *tr,int x,int v)
int sum(int *tr,int x)
void add(int x,int y)
void dfs(int u,int fa)
} r[u]=stm;
}int lca(int x,int y)
void calcans(int x,int y,int lc)
int main()
dfs(1,-1);
scanf("%d",&m);
for(int i=1;i<=m;++i)
return 0;
}
NOIP模擬 相交(樹鏈剖分 樹狀陣列維護)
我已經無力爆粗了。md這c 怎麼能在編譯了 執行了以後,最後發現居然是之前的版本?喵喵喵?考慮兩條路徑相交,那麼其中一條的lca一定在另一條路徑上。所以開兩個樹狀陣列維護之前路徑的資訊和之前路徑的lca的位置。統計一下,然後更新,再做下一條路徑即可。includeusing namespace st...
LCA 樹狀陣列 樹上RMQ
思路 首先求出樹上dfs序列,並且標記樹上每個節點開始遍歷以及最後回溯遍歷到的時間戳,由於需要修改樹上的某兩個節點之間的權值,如果parent v u,那麼說明修改之後的v的子樹到當前根的距離都會改變,由於遍歷到v時有開始時間戳以及結束時間戳,那麼處於這個區間所有節點都會影響到,於是我們可以通過陣列...
LCA 樹狀陣列 樹上RMQ
思路 首先求出樹上dfs序列,並且標記樹上每個節點開始遍歷以及最後回溯遍歷到的時間戳,由於需要修改樹上的某兩個節點之間的權值,如果parent v u,那麼說明修改之後的v的子樹到當前根的距離都會改變,由於遍歷到v時有開始時間戳以及結束時間戳,那麼處於這個區間所有節點都會影響到,於是我們可以通過陣列...