1. 程式人生 > >【LOJ2865】「IOI2018」狼人

【LOJ2865】「IOI2018」狼人

【題目連結】

【思路要點】

  • 問題等價於從起點出發只經過 L,L+1,L+2,...,NL,L+1,L+2,...,N 能夠到達的點和終點出發只經過 1,2,3,...,R1,2,3,...,R 能夠到達的點是否有交。
  • 建出原圖的最小/最大生成樹的 $Kruskal $ 重構樹,這兩個點集對應了兩棵樹上的某兩個子樹。
  • 對於點集根據最小生成樹的 $Kruskal $ 重構樹的 DFSDFS 序進行重標號,離線詢問,在最大生成樹的 $Kruskal $ 重構樹上線段樹合併,即可查詢子樹內是否存在標號在某一個區間中的點,從而判斷兩個點集是否有交。
  • 時間複雜度 O(NLogN)O(NLogN)

【程式碼】

#include "werewolf.h"
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXLOG = 20;
const int MAXP = 1e7 + 5;
struct SegmentTree {
	struct Node {
		int lc, rc;
		int sum;
		bool leaf;
	} a[MAXP];
	int size, n;
	void init(
int x) { n = x; size = 0; } void update(int root) { a[root].sum = a[a[root].lc].sum + a[a[root].rc].sum; } void modify(int &root, int l, int r, int pos) { if (root == 0) root = ++size; if (l == r) { a[root].sum = 1; a[root].leaf = true; return; } int mid = (l + r) / 2; if
(mid >= pos) modify(a[root].lc, l, mid, pos); else modify(a[root].rc, mid + 1, r, pos); update(root); } void modify(int &root, int val) { return modify(root, 1, n, val); } int merge(int x, int y) { if (x == 0 || y == 0) return x + y; if (a[x].leaf) { a[x].sum += a[y].sum; return x; } a[x].lc = merge(a[x].lc, a[y].lc); a[x].rc = merge(a[x].rc, a[y].rc); update(x); return x; } void join(int &to, int from) { to = merge(to, from); } int query(int root, int l, int r, int ql, int qr) { if (root == 0) return 0; if (l == ql && r == qr) return a[root].sum; int mid = (l + r) / 2, ans = 0; if (mid >= ql) ans += query(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) ans += query(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); return ans; } int query(int root, int l, int r) { return query(root, 1, n, l, r); } } ST; vector <int> ans, a[MAXN], b[MAXN], c[MAXN]; vector <int> home[MAXN], ql[MAXN], qr[MAXN]; //a : graph, b : tree1, c : tree2. int n, m, q, f[MAXN], root[MAXN]; int fatherb[MAXN][MAXLOG]; int fatherc[MAXN][MAXLOG]; int timer, dfn[MAXN], rit[MAXN]; int F(int x) { if (f[x] == x) return x; else return f[x] = F(f[x]); } void dfs(int pos, int fa) { fatherb[pos][0] = fa; for (int i = 1; i < MAXLOG; i++) fatherb[pos][i] = fatherb[fatherb[pos][i - 1]][i - 1]; dfn[pos] = ++timer; for (unsigned i = 0; i < b[pos].size(); i++) dfs(b[pos][i], pos); rit[pos] = timer; } void work(int pos) { ST.modify(root[pos], dfn[pos]); for (unsigned i = 0; i < c[pos].size(); i++) { work(c[pos][i]); ST.join(root[pos], root[c[pos][i]]); } for (unsigned i = 0; i < home[pos].size(); i++) if (ST.query(root[pos], ql[pos][i], qr[pos][i]) != 0) ans[home[pos][i]] = 1; } vector <int> check_validity(int tn, vector <int> x, vector <int> y, vector <int> s, vector <int> t, vector <int> l, vector <int> r) { n = tn, m = x.size(), q = s.size(); ans.resize(q); for (int i = 0; i <= m - 1; i++) { x[i]++, y[i]++; a[x[i]].push_back(y[i]); a[y[i]].push_back(x[i]); } for (int i = 1; i <= n; i++) f[i] = i; for (int i = 1; i <= n; i++) { for (unsigned j = 0; j < a[i].size(); j++) if (a[i][j] <= i && F(a[i][j]) != i) { b[i].push_back(F(a[i][j])); f[F(a[i][j])] = i; } } dfs(n, 0); for (int i = 1; i <= n; i++) f[i] = i; for (int i = n; i >= 1; i--) { for (unsigned j = 0; j < a[i].size(); j++) if (a[i][j] >= i && F(a[i][j]) != i) { c[i].push_back(F(a[i][j])); fatherc[F(a[i][j])][0] = i; f[F(a[i][j])] = i; } } for (int i = 1; i <= n; i++) for (int j = 1; j < MAXLOG; j++) fatherc[i][j] = fatherc[fatherc[i][j - 1]][j - 1]; for (int i = 0; i <= q - 1; i++) { s[i]++, t[i]++; l[i]++, r[i]++; if (s[i] < l[i] || t[i] > r[i]) continue; int pos = t[i]; for (int j = MAXLOG - 1; j >= 0; j--) if (fatherb[pos][j] != 0 && fatherb[pos][j] <= r[i]) pos = fatherb[pos][j]; int tl = dfn[pos], tr = rit[pos]; pos = s[i]; for (int j = MAXLOG - 1; j >= 0; j--) if (fatherc[pos][j] != 0 && fatherc[pos][j] >= l[i]) pos = fatherc[pos][j]; home[pos].push_back(i); ql[pos].push_back(tl); qr[pos].push_back(tr); } ST.init(n); work(1); return ans; }

相關推薦

LOJ2865IOI2018

【題目連結】 【思路要點】 問題等價於從起點出發只經過 L,L+1,L+2,...,NL,L+1,L+2,...,NL,L+1,L+2,...,N 能夠到達的點和終點出發只經過 1,2,3,...,R1,2,3,...,R1,2,3,...,R 能夠到達的

LOJ2262CTSC2017網路

【題目連結】 點選開啟連結 【思路要點】 首先,本題一點重要的觀察是,新建的路徑的兩個端點必定在樹的直徑上,若一個方案新建路徑的兩個端點有一個不在直徑上,我們令其向直徑靠近,不會使答案變劣。 因此,我們可以將直徑拿出來

LOJ2264CTSC2017吉夫特

【題目連結】 點選開啟連結 【思路要點】 由 L u

LOJ2263CTSC2017遊戲

【題目連結】 點選開啟連結 【思路要點】 仿照題目的第二問的解法,我們先來考慮本題的平方做法。 令 B

LOJ2950NOIP2018鋪設道路

【題目連結】 點選開啟連結 【思路要點】 有一個顯然正確的貪心:處理區間 [

LOJ3043ZJOI2019線段樹

https lse 當前 row clas 標記 int push ret 題面 問題可以轉化為每次區間覆蓋操作有 \(\frac{1}{2}\) 的概率進行,求標記和的期望。於是我們只要求出所有點有標記的概率即可。 我們設 \(f_i\) 表示節點 \(i\) 有標記的概

刷題LOJ 2863 IOI2018組合動作

sample tst ring 註意 數據 -i swe 過程 格式 題目描述 你在玩一個動作遊戲。遊戲控制器有 \(4\) 個按鍵,A、B、X 和 Y。在遊戲中,你用組合動作來賺金幣。你可以依次按這些按鍵來完成一個組合動作。 這個遊戲有一個隱藏的按鍵序列,可以表示為由這

loj6177美團 CodeM 初賽 Round B送外賣2

ace using print font names -s 統計 ase round 題目描述 一張$n$個點$m$條邊的有向圖,通過每條邊需要消耗時間,初始為$0$時刻,可以在某個點停留。有$q$個任務,每個任務要求在$l_i$或以後時刻到$s_i$接受任務,並在$r_

loj6191美團 CodeM 復賽配對遊戲 概率期望dp

size 減少 四舍五入 一行 () fine ros sof 多少 題目描述 n次向一個棧中加入0或1中隨機1個,如果一次加入0時棧頂元素為1,則將這兩個元素彈棧。問最終棧中元素個數的期望是多少。 輸入 一行一個正整數 n 。 輸出 一行一個實數,表示期望剩下的

luogu P4711 化學相對分子質量 題解

strlen nan .org cstring 處理 fan using str uri 題目鏈接:https://www.luogu.org/problemnew/show/P4711 要細心模擬 #include <cstdio> #include <

Java深入理解Java虛擬機器學習筆記(1) - Java語言發展趨勢

這本書寫的比較早,現在這些功能都已經不同程度的實現了。 1、模組化     JDK9之前的版本都是一個整體,使用者可能只需要使用一個小功能,但他不得不下載整個JDK。不能滿足定製化需求,顯然Java語言的發展因此大大受限。   所以,Sun公司在OpenJDK建立了一個Jigsaw(拼圖)的專案來推動模

Java深入理解Java虛擬機器學習筆記(2)-記憶體管理

 一、執行時資料區   JVM在執行Java程式的時候,將其執行時資料區劃分為若干不同區域。它們的用途和建立及銷燬的時間不同。      1、程式計數器(Program Counter Register)     是一塊很小的記憶體空間。當執行緒執行的是Java方法,它記錄的是當前正在執行的

LOJ2322清華集訓 2017Hello world!

【題目連結】 點選開啟連結 【思路要點】 一個 1

LOJ2328清華集訓 2017避難所

【題目連結】 點選開啟連結 【思路要點】 令 x

LOJ2326清華集訓 2017簡單資料結構

【題目連結】 點選開啟連結 【思路要點】 注意到答案是 O

LOJ2323清華集訓 2017小 Y 和地鐵

【題目連結】 點選開啟連結 【思路要點】 很不錯的腦洞題。 附上官方題解。 時間複雜度 O

LOJ2324清華集訓 2017小 Y 和二叉樹

【題目連結】 點選開啟連結 【思路要點】 答案的第一位一定是編號最小的度數不為 3

LOJ2329清華集訓 2017我的生命已如風中殘燭

【題目連結】 點選開啟連結 【思路要點】 一個直觀的思路是模擬該過程,當路上遇到環的時候通過類似取模的手段加速。 注意到每繞一個環

LOJ2331清華集訓 2017某位歌姬的故事

【題目連結】 點選開啟連結 【思路要點】 注意到若一個位置被兩種音高 a

LOJ2330清華集訓 2017榕樹之心

【題目連結】 點選開啟連結 【思路要點】 首先,樹是二分圖,只有一側的點可能成為心。 維護每一棵子樹會產生的向下推動的次數可能的最大值