樹上路徑(path)

2021-09-10 22:30:13 字數 3385 閱讀 9460

berland,有n

個城堡。

每個城堡恰好屬於乙個領主。不同的城堡屬於不同的領主。在所有領主中有乙個是國王,其他的每個領主都直接隸屬於另一位領主,並且間接隸屬於國王。一位領主可以擁有任意數量的下屬。這些城堡被一些雙向的道路連線。兩個城堡是連線的當且僅當他們的主人中一位直接隸屬於另一位。

每一年,在

berland

會發生以下兩件事中的一件:

1.野蠻人攻擊了城堡

c。這是城堡

c第一次也會是最後一次被攻擊,因為野蠻人從來不攻擊同一座城堡超過一次。

2.乙個騎士從城堡

a出發前往到城堡

b。騎士從不重複經過同一座城堡,因此他的路線是唯一確定的。

現在考慮第二類事件。由於從城堡a到

b的路途遙遠,每個騎士會在他經過的某個城堡停下來休息一次。根據規則,騎士不能停留在第

y 年以後受到過攻擊的城堡中。所以,騎士選擇了途徑的第

k個從第

y+1 

年開始到現在(當時)沒有被攻擊過的城堡(不算城堡a和

b)。你,偉大的歷史學家,知道

berland

歷史上的所有

m個事件。請你計算,每個騎士是在哪個城堡休息的。如果在從城堡

a到城堡

b的路上少於

k座城堡,那麼你可以斷定有關這個騎士的記載是有誤的。

第一行包含乙個整數

n,表示城堡數目。

第二行包含

n個整數,依次表示編號為

1...n 

的城堡領主的上級。特別的,國王沒有上級,故用

0 表示。

第三行包含乙個整數

m,表示事件數目。

接下來m

行,每行描述乙個事件:

若是第1

類事件,則包含兩個整數,依次是1,

ci;若是第2

類事件,則包含五個整數,依次是2,

ai,bi,

ki,yi。

輸出若干行,每行乙個整數,依次表示每個騎士休息的城堡編號。若騎士不可能休息,則輸出-1。

3

0 1 2

52 1 3 1 0

1 22 1 3 1 0

2 1 3 1 1

2 1 3 1 2

2

-1-1

2

【資料規模和約定】

20%的資料:

1 ≤ n, m ≤ 1000;另有

30%的資料:有且僅有乙個領主沒有下屬;

100%

的資料:

1 ≤ n, m ≤ 105,

1 ≤ ai, bi, ci, ki ≤ n

,0 ≤ yi  <  i

,每個事件中

ai ≠ bi

。2014北京省選集訓day2

solution

樹剖,轉化為區間問題

對於每乙個時間開一棵主席樹,下標1~n,表示i是否被毀壞

對於詢問,取出第y棵樹和現在的樹

如果有變動,就不能住。

比較煩的就是從b到lca的路徑要求top-k+1大,

因為它是倒過來的

還有ab不能住,需要加一加

#include#include#include#include#include#include#define maxn 100005

using namespace std;

int n,m,head[maxn],t1,t2,tot,dfn[maxn],deep[maxn],son[maxn],size[maxn];

int top[maxn],fa[maxn],sc,total,dy[maxn],op,root[maxn],t,a,b;

int lca,a1,b1,li,ri,rk,las,rak,num1,num2,ff;

struct notree[maxn*23];

struct nodee[maxn*2];

void lj(int t1,int t2)

void dfs1(int k,int fath)

}size[k]=sz+1;son[k]=gp;

}void dfs2(int k)

for(int i=head[k];i;i=e[i].nex)

}}void wh(int k)

void dfs(int &k,int la,int l,int r,int pl)

tree[k].ls=tree[la].ls,tree[k].rs=tree[la].rs;

int mid=l+r>>1;

if(pl<=mid)dfs(tree[k].ls,tree[la].ls,l,mid,pl);

else dfs(tree[k].rs,tree[la].rs,mid+1,r,pl);

wh(k);

}int ch(int k,int la,int l,int r)

int mid=l+r>>1;

int su=0;

if(li<=mid)su+=ch(tree[k].ls,tree[la].ls,l,mid);

if(ri>mid)su+=ch(tree[k].rs,tree[la].rs,mid+1,r);

return su;

}int ask(int k,int la,int l,int r,int fs)

else return ask(tree[k].ls,tree[la].ls,l,mid,fs);

}int main()

dfs1(1,0);top[1]=1;dfs2(1);

cin>>m;

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

else

else rk-=num;

a=fa[t1],t1=top[a];

}if(fl)continue;

li=dfn[lca],ri=dfn[a];

num=ch(root[i],root[las],1,n);

if(num>=rk)

// right

fl=0;rk=rak;

b=b1,t2=top[b];

while(t2!=top[lca])

else rk-=num;

b=fa[t2],t2=top[b];

}if(fl)continue;

li=dfn[lca],ri=dfn[b];

num=ch(root[i],root[las],1,n);

if(num>=rk)}}

return 0;

}

posted @

2018-08-30 19:51

liankewei 閱讀(

...)

編輯收藏

5055 樹上路徑

給定一顆 n 個結點的無根樹,每個點有乙個點權,定義一條路徑的價值為路徑上的點權和 路徑的點權最大值。給定引數 p,求有多少不同的樹上簡單路徑,滿足它的價值恰好是 p 的倍數。data constraint n 105,p 107 考慮點分治。對於當前的分治重心,把所有以它為起點的路徑取出來,按照路...

題解 樹上路徑

一棵樹的構造過程為 首先以1號點為根,然後依次加入2 n號點。加入i號點時,在1 i 1點中選擇乙個點為f i 將i號點與其相連線。yuri想要求出,每次加點之後路上的最長路徑長度。第一行乙個整數n,表示樹的節點個數。第二行n 1個整數,第i個整數表示f i 1 一行n 1個整數,分別表示加完2 n...

JZOJ5055 樹上路徑

給定一棵 n 個節點的無根樹,每個點都有乙個非負整數的權值va li,定義一條路徑的價值為路徑上的點權和減去路徑的點權最大值。給定引數 p 請求出樹上有多少條價值是 p的倍數的路徑。注意 單點也算路徑。並且路徑 u v 和 v u 只算一次。1 n 105 1 p 107,0 va li 10 9 ...