樹上差分的兩種形式(相遇 or 行程的交集 題解)

2022-05-01 13:18:08 字數 2349 閱讀 1255

emm,這很noip...

寫這個的原因是今天考試乙個sb差分樹題居然槓了個樹剖上去,殺雞用了牛刀。

而且不止一次了...總是想不到子樹和這種差分,淦

anyway,簡單寫寫吧。

三重封裝

轉化後的問題都能用dfs序+樹狀陣列解決。(在上文**中,樹狀陣列用bit封裝,st, ed是dfs序)

本質:在序列上,字首和、字尾和均能解決這兩個問題。

而之所以在樹上這兩種形式求解的問題出現不同,是因為與序列相比,樹是上小下大的。

這道題綜合的考察了兩種差分,成功把我幹翻(

[出處不明] 相遇 or 行程的交集

description

豪哥生活在乙個n個點的樹形城市裡面,每一天都要走來走去。雖然走的是比較的多,但是豪哥在這個城市裡面的朋友並不是很多。

當某一天,猴哥給他展現了一下大佬風範之後,豪哥決定要獲得一些交往機會來提公升交往能力。豪哥現在已經物色上了一條友,打算和它(豪哥並不讓吃瓜群眾知道性別)交往。豪哥現在spy了一下這個人的所有行程起點和終點,豪哥打算從終點開始走到起點與其相遇。但是豪哥是想找話題的,他想知道以前有多少次行程和此次行程是有交集的,這樣豪哥就可以搭上話了。這個路徑與之前路徑的有交集數量作為豪哥此次的交往機會。

但是豪哥急著要做交往準備,所以算什麼交往機會的小事情就交給你了。

input

第一行乙個正整數n表示節點個數。

接下來n-1行,每行兩個正整數分別是u,v表示節點u和v之間有連邊。

接下來一行乙個 正整數m表示路徑個數。

然後有m行,每行兩個正整數分別是u,v分別表示u到v之間有一條路徑。

output

輸出共m行,每行乙個整數,第i行表示豪哥在這條路徑上獲得的交往機會。

sample input

5

1 21 3

3 43 5

44 5

4 21 3

1 2

sample output

012

2

hint

【資料範圍與約定】

對於20%的資料n,m≤2000

對於另外20%的資料n,m≤50000

對於另外10%的資料n,m≤200000,保證樹形結構是一條鏈

對於另外50%的資料n,m≤200000

簡要題意:給你一棵樹,然後按順序輸入若干條路徑。問每次輸入路徑時該路徑與前面已經輸入的多少條路徑有交集。

主要要想到把兩條樹上路徑有交集轉換為其中某條路徑的lca被另一條路徑所覆蓋

於是對於當前輸入的路徑,分當前路徑覆蓋了多少個之前路徑的lca當前路徑的lca被之前多少個路徑覆蓋討論即可。前者是單點修改&鏈查詢,後者是鏈修改&單點查詢,按前文的方法做就可以了。

注意特判lca重疊的情況,見**。

#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;

typedef long long ll;

typedef vectorvector;

typedef vector::iterator vecit;

ll rd()

while(c>='0'&&c<='9') ans=ans*10+c-'0',c=getchar();

if(fh) ans=-ans;

return ans;

}ll lowbit(ll x)

const ll ptn=2e5+5;

class bit

bit(ll n)

void add(ll p,ll w)

ll query(ll p)

};ll n;

vector edge[ptn];

ll fa[ptn],dep[ptn],sz[ptn],son[ptn];

ll st[ptn],ed[ptn];ll dn;

void dfs1(ll u,ll father,ll depth)

ed[u]=++dn;

}ll tp[ptn];

void dfs2(ll u,ll toop)

}ll lca(ll u,ll v){

while(tp[u]!=tp[v]){

if(dep[tp[u]]2020/10/24

樹上差分的兩種實現形式

簡單理解樹上差分 點,邊 關於樹上差分,我在這推薦一道題目poj 3417 題目翻譯 樹上差分用來解決點的覆蓋或者邊的覆蓋的問題,需分別運用點的差分或者邊的差分。先從例題入手 給定點數為n,邊數為n 1的樹 無向邊且無重邊 先有m條連線a,b的非樹邊,求每條 樹邊 被 非樹邊 覆蓋了多少次?邊的差分...

C C 的兩種多型形式

1 2 test.cpp4 5 created by mac on 15 8 11.6 7 8 include9 include10 using namespace std 11class person 基類person12 25person person 26 person person stri...

include的兩種指令形式

在程式設計過程中不在意的細節 搬運於c程式設計 include include stdio.h include使用尖括號的形式時,編譯系統從存放c編譯系統的子目錄中去找所要包含的檔案如 stdio.h 這稱為 標準方式 若使用 include指令是為了使用系統庫函式,因而要包含系統提供的相應標頭檔案...