刷題 LCA set 異象石

2022-08-13 21:51:11 字數 3048 閱讀 5341

被指標折磨得死去活來......

所以這裡具體分析指標

題目描述

adera 是 microsoft 應用商店中的一款解謎遊戲。

異象石是進入 adera 中異時空的引導物,在 adera 的異時空中有一張地圖。這張地圖上

有 n 個點,有 n-1 條雙向邊把它們連通起來。起初地圖上沒有任何異象石,在接下來的 m

個時刻中,每個時刻會發生以下三種型別的事件之一:

1. 地圖的某個點上出現了異象石(已經出現的不會再次出現);

2. 地圖某個點上的異象石被摧毀(不會摧毀沒有異象石的點);

3. 向玩家詢問使所有異象石所在的點連通的邊集的總長度最小是多少。

請你作為玩家回答這些問題。

輸入格式

第一行有乙個整數 n,表示點的個數。

接下來 n-1 行每行三個整數 x,y,z,表示點 x 和 y 之間有一條長度為 z 的雙向邊。

第 n+1 行有乙個正整數 m。

接下來 m 行每行是乙個事件,事件是以下三種格式之一:

+ x 表示點 x 上出現了異象石

- x 表示點 x 上的異象石被摧毀

? 表示詢問使當前所有異象石所在的點連通所需的邊集的總長度最小是多少。

輸出格式

對於每個 ? 事件,輸出乙個整數表示答案。

先看思路:

這兩道題是一模一樣的題,只不過輸入格式改了一下,然後異象石這道題輸出的時候把答案除以2。不過我最初做的是異象石這道題,所以就按照這道題來解釋了。

題目大意就是,給一棵樹,要求動態維護乙個值:使所選出的點連通的邊的最小權值和(最小的意思就是不需要更多的邊,已經達到連通狀態,因為是樹,所以這個邊集是唯一的)。有加入和刪除所選定的點的操作。

如圖,對於當前這棵樹:

我們選擇的節點為圖中標號1、2、3的三個節點,那麼√標註的邊的權值和就是我們所求的。設lca(a, b)為a,b到兩個點最近公共祖先的路徑長度之和。那麼,這些邊的權值和就是(lca(1,2)+lca(2,3)+lca(3,1))/2。並發現這個和是這樣子的: 

這一圈,就是尋寶遊戲的答案,就是異象石的答案乘以2的結果。可以想到,對於這樣的點集,要求的這個「圈」,可以通過兩兩點之間的lca加和得到。對於乙個點的序列a[1]~a[i],就是lca(a[1],a[2])+lca(a[2],a[3])+……+lca(a[i-1],a[i])+lca(a[i],1)。而這個序列點的順序是什麼?dfs序。畫一畫圖很容易就明白了。

所以,我們先預處理出這棵樹節點的dfs序的序號(就是在dfs過程中,這個點是第幾個被訪問到的)。在維護的過程中,假設加入乙個點後,它的位置是i,那麼對於答案ans,我們需要做的改變就是ans += lca(a[i-1],a[i])+lca(a[i],a[i+1])-lca(a[i-1],a[i+1]);這個也很容易明白吧。相反,如果刪除乙個點,它原本的位置是i,只需要ans -= lca(a[i-1],a[i])+lca(a[i],a[i+1])-lca(a[i-1],a[i+1]);【切記不要每次修改只搞乙個bool陣列記錄而每次詢問都全部重新計算,而是要動態維護ans】

那麼用什麼來做到維護a序列呢?stl裡的set就可以。s.insert(x);插入x, s.erase(x);刪除x, s.lower_bound(x);返回乙個迭代器,指向集合中第乙個大於或等於x的元素。集合鍵值就是dfs序的編號,用這些函式就可以維護a序列,並且求出a[i],a[i-1],a[i+1]是哪些節點。

上自己的**:

#include#include

#include

#include

#define ll long long

using

namespace

std;

inline

intread()

intn,m;

const

int n=1e5+3

;int

tot,head[n];

struct

node

e[n<<1

];void add(int u,int

v,ll w)

intdep[n],cnt,dfn[n],bac[n];

int fa[n][18];ll pth[n][18

];void dfs1(int rt,intf)}

ll ans;

sets;

ll lca(

int xx,int

yy)int

main()

dfs1(

1,0);

m=read();

char

ch;

while(m--)

set ::iterator nx=s.upper_bound(dfn[find_x]),pre=nx;

--pre;

if(nx==s.end() ) nx=

s.begin() ;

if(nx==s.begin() ) pre=s.end() ,pre--

;

int u=bac[*pre],v=bac[*nx]; //

加上乙個*就可以當值使用

ans+=lca(u,find_x)+lca(find_x,v)-lca(u,v);

s.insert(dfn[find_x]);

}else

if(ch=='-'

)

}return0;

}

(1)使用s.lower_bound((int)x),的時候,返回的位置要用 

set::iterator it 記錄

(2)返回結果可能為s.begin(),s.end(),

如果要獲取前乙個和後乙個,都要討論,漏乙個就re

(3)位置前寫*,可以直接當int使用

(4)不可以寫什麼pos+1,只能++或者--

異象石 引理證明

adera是microsoft應用商店中的一款解謎遊戲。異象石是進入adera中異時空的引導物,在adera的異時空中有一張地圖。這張地圖上有n個點,有n 1條雙向邊把它們連通起來。起初地圖上沒有任何異象石,在接下來的m個時刻中,每個時刻會發生以下三種型別的事件之一 地圖的某個點上出現了異象石 已經...

Loj題解 10132 異象石

目錄給定一棵 n 個結點的樹,邊有邊權,三種操作 乙個很神奇的結論 記乙個陣列 dfn 用來存dfs序的每個節點 設現有的被標記的點的dfs序從小到大排序後的集合為 設兩個點 u,v 的距離為 dis 那麼答案為 dis dis dis x k dis 的一半 那麼我們用乙個資料結構維護標記的點的序...

NOIP模擬賽 異象石

adera是microsoft應用商店中的一款解謎遊戲。異象石是進入adera中異時空的引導物,在adera的異時空中有一張地圖。這張地圖上有n個點,有n 1條雙向邊把它們連通起來。起初地圖上沒有任何異象石,在接下來的m個時刻中,每個時刻會發生以下三種型別的事件之一 1.地圖的某個點上出現了異象石 ...