1. 程式人生 > >[jzoj]5966. 【NOIP2018提高組D2T3】保衛王國(矩陣乘法+鏈剖維護線段樹 或 倍增DP)

[jzoj]5966. 【NOIP2018提高組D2T3】保衛王國(矩陣乘法+鏈剖維護線段樹 或 倍增DP)

Problem

  • 弱化版動態詢問一棵樹的最小覆蓋集.

  • 每次只選擇其中某兩個點必選或必不選,且詢問獨立.

Data constraint

  • n , m 1 0
    5 n,m\le 10^5

Solution

【動態DP = 樹鏈剖分 + 線段樹 + 矩陣轉移】
  • 這好像是 W C 2018

    WC_{2018} 搞出來的一個新玩意兒,挺神奇的.

  • 首先,最小覆蓋集 = 全集 - 最大獨立集.

  • 其次,一個點必選或不必選,可以直接把他的權值賦值為無窮大,或無窮小.

  • 這樣,問題完美轉化為求解一棵樹的最大獨立集.

  • 一個小學四年級的DP是 f [

    i ] [ 0 / 1 ] f[i][0/1] 表示 i i 點選或不選,最大收益.

  • 先樹剖一下,然後一個初三的DP是,設一個 g [ i ] [ 0 / 1 ] g[i][0/1] 表示與 f f 含義相同,唯獨不能用重兒子去轉移.

  • 這樣有什麼好處?

  • 我們不妨用 i i 表示當前要計算 f f 的點,假設它線上段樹上的編號也是 i i ,那麼它的重兒子線上段樹上的編號就是 i + 1 i+1 .

  • 那麼你可以寫出這樣的兩條式子: f [ i ] [ 0 ] = g [ i ] [ 0 ] + m a x ( f [ i + 1 ] [ 0 ] , f [ i + 1 ] [ 1 ] ) f[i][0] = g[i][0] + max(f[i+1][0], f[i+1][1]) f [ i ] [ 1 ] = g [ i ] [ 1 ] + f [ i + 1 ] [ 0 ] f[i][1] = g[i][1] + f[i+1][0] .

  • 然後神奇的一步出現,你考慮把它寫成矩陣轉移的形式,會變成: [ g i , 0 g i , 0 g i , 1 0 ] [ f i + 1 , 0 f i + 1 , 1 ] = [ f i , 0 f i , 1 ] \begin{bmatrix}g_{i, 0} & g_{i, 0} \\g_{i, 1} & 0\end{bmatrix} * \begin{bmatrix}f_{i + 1, 0} \\ f_{i + 1, 1}\end{bmatrix} = \begin{bmatrix}f_{i, 0} \\ f_{i, 1}\end{bmatrix}

  • 這裡需要注意,普通的矩陣乘法形式是形如: C i , j = k = 1 n A i , k B k , j C_{i, j} = \sum_{k = 1}^{n} A_{i, k} * B_{k, j}

  • 而這裡,我們把它改變一下,變成 C i , j = max k = 1 n ( A i , k + B k , j ) C_{i, j} = \max_{k = 1}^{n} (A_{i, k} + B_{k, j})

  • 並且發現後者也是滿足所謂的結合律的.

  • 那麼不難發現,其實一個點的答案,就是它所在重鏈的每一個節點的g矩陣乘起來.

  • 因為滿足結合律,所以剛好可以用鏈剖+線段樹來維護.

  • 然後考慮修改,假設修改一個點 x x 的權值,那麼其實父親 g g 矩陣不會改變,I.e.其所在重鏈的所有祖先的 g g 矩陣不會改變.

  • 會改變的僅僅是 x x 本身的 g g 矩陣,以及所在重鏈每一個祖先的 f f 值(答案).

  • 因為會影響祖先的 f f 值,所以在經過完這條重鏈後走一條輕邊到達另一條重鏈時,會影響到那條鏈上的 g g 矩陣.

  • 所以我們的修改步驟就很明確了:

    • 先修改當前權值,然後處理一下 g g 矩陣.

    • 然後進入迴圈,一直向頂端去修改.

  • 具體實現的時候,實際上我們可以記錄一個 b [ x ] b[x] 表示 x x 這個點線上段樹上的編號.

  • 那麼修改一個點的 g g 矩陣直接修改即可,然後暴力的往上跳,進行合併即可.

  • 這樣常數會小很多,且可以優化一下這個轉移,把它不要真的寫成取max,這樣太慢.

  • 參考程式碼:

#include <cstdio>
#include <cstring>
#include <iostream>

#define ll long long
#define F(i, a, b) for (ll i = a; i <= b; i ++)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define mem(a, b) memset(a, b, sizeof a)
#define mec(a, b) memcpy(a, b, sizeof a)
#define mx(a, b) ((a) = max(a, b))
#define get getchar()

#define M (st + en >> 1)
#define Ls (x << 1)
#define Rs (Ls | 1)

const ll N = 2e5 + 10, T = 4 * N, W = 1e15;

using namespace std;

ll n, m, u, v, a, x, b, y, t, cnt, Sum, sum, DFN[N], V[N]; char ch[10];
ll sz[N], fa[N], Son[N], top[N], dfn[N], f[N][2], B[N], D[N];
ll tov[T], nex[T], las[N], tot, S0, S1;

struct mat {
	ll g[2][2];
	mat() { mem(g, 0); }
	inline mat operator * (const mat &b) const { mat c;
		c.g[0][0] = max(g[0][0] + b.g[0][0], g[0][1] + b.g[1][0]);
		c.g[0][1] = max(g[0][0] + b.g[0][1], g[0][1] + b.g[1][1]);
		c.g[1][0] = max(g[1][0] + b.g[0][0], g[1][1] + b.g[1][0]);
		c.g[1][1] = max(g[1][0] + b.g[0][1], g[1][1] + b.g[1][1]);
		return c;
	}
} tr[T], TR
            
           

相關推薦

[jzoj]5966. NOIP2018提高D2T3保衛王國矩陣乘法+維護線段 倍增DP

Problem 弱化版動態詢問一棵樹的最小覆蓋集. 每次只選擇其中某兩個點必選或必不選,且詢問獨立. Data constraint n

5966. NOIP2018提高D2T3保衛王國

Description Z國有n座城市,n-1條雙向道路,每條雙向道路連線兩座城市,且任意兩座城市都能通過若干條道路相互到達。 Z國的國防部長小Z要在城市中駐紮軍隊。駐紮軍隊需要滿足如下幾個條件: ①一座城市可以駐紮一支軍隊,也可以不駐紮軍隊。 ②由道路直接連線的兩座城市中至少要有一座城

JZOJ5966NOIP2018提高D2T3保衛王國並查集

題目 還是懶得把題目放上來了。 大意:給你一棵帶點權的樹,你要花費一些代價選擇一些點使得相鄰的兩個點至少有一個被選。 然後有很多個詢問,每個詢問強制兩個點的狀態,問強制了這兩個點的狀態後的方案。 比賽思路 沒時間了,沒時間了…… 匆匆打個44分的暴力就好了。 結果混淆了

NOIP2018提高D2T3保衛王國

抱歉,本人蒟蒻沒能做出,不過可給標程,orz大佬 const maxn=100000;inf=trunc(1e+12)-1; var f : array[0..maxn,0..17,0..1,0..1]of int64; up,dw : array[0..maxn,0..

JZOJ-senior-5964. NOIP2018提高D2T1旅行

Time Limits: 1000 ms Memory Limits: 524288 KB Description 小Y是一個愛好旅行的OIer。她來到X國,打算將各個城市都玩一遍。 小Y瞭解到,X國的n個城市之間有m條雙向道路。每條雙向道路連線兩個城市。不存在兩條連線同一對城市

JZOJ-senior-5963. NOIP2018提高D1T3賽道修建

Time Limits: 1000 ms Memory Limits: 524288 KB Description C城將要舉辦一系列的賽車比賽。在比賽前,需要在城內修建m條賽道。 C城一共有n個路口,這些路口編號為1,2,…,n ,有n-1 條適合於修建賽道的雙向通行的道路,每

JZOJ-senior-5962. NOIP2018提高D1T2貨幣系統

Time Limits: 1000 ms Memory Limits: 524288 KB Description 在網友的國度中共有 n 種不同面額的貨幣,第 i 種貨幣的面額為 a[i],你可以假設每一種貨幣都有無窮多張。為了方便,我們把貨幣種數為 n、面額陣列為 a[1…n

JZOJ 5878. NOIP2018提高模擬9.22電路圖 A

Description nodgd 要畫一個電路圖。 這是一個很簡單的電路圖,所有的元件都是串聯關係,從整體來看就是一個環狀的結構。畫電路圖有很多要求,nodgd 為了畫得好看就又添加了一些 額外的要求。所有要求歸結起來有以下幾點: 1、這個環狀電路上有n個雙端

NOIP2018提高D2T2填數遊戲

Description 小D特別喜歡玩遊戲。這一天,他在玩一款填數遊戲。 這個填數遊戲的棋盤是一個n*m的矩形表格。玩家需要在表格的每個格子中填入一個數字(數字0或者數字1),填數時需要滿足一些限制。 下面我們來具體描述這些限制。 為了方便描述,我們先給出一些定義: 我們用每個格子的

NOIP2018提高D1T3賽道修建

唉,這題考場想到了,就是細節搞爆了。。。 主要是二分答案然後判一下,每次深搜(類似貪心)即可。 #include<cstdio> #include<cstring> #include<algorithm> using namespace

5964. NOIP2018提高D2T1旅行

Description 小Y是一個愛好旅行的OIer。她來到X國,打算將各個城市都玩一遍。 小Y瞭解到,X國的n個城市之間有m條雙向道路。每條雙向道路連線兩個城市。不存在兩條連線同一對城市的道路,也不存在一條連線一個城市和它本身的道路。並且,從任意一個城市出發,通過這些道路

5961. NOIP2018提高D1T1鋪設道路

Time Limits: 1000 ms Memory Limits: 524288 KB Description 春春是一名道路工程師,負責鋪設一條長度為 n 的道路。 鋪設道路的主要工作是填平下陷

NOIP2018提高D1T1鋪設道路

這題不用講了吧,一遍掃直接過 #include<cstdio> using namespace std; int n,a[100010],ans=0; inline int read() { int x=0; char c=getchar(); while

NOIP2018提高D1T2貨幣系統

這題就是送分的。直接記憶化深搜即可 但有些人竟然跟我打的不一樣,我也貼一下標吧 深搜: #include<cstdio> #include<cstring> #include<algorithm> using namespace st

NOIP2018提高D2T1旅行

這一道題嘛,水。分類討論即可 mn 暴力刪邊判 mn-1 直接做即可 #include<cstdio> #include<string> #include<cstring> #include<algorithm> using

JZOJ5965NOIP2018提高D2T2填數遊戲

題目 作為NOIP2018的題目,我覺得不需要把題目貼出來了。 大意就是,在一個 n ∗ m

jzoj5899 NOIP2018模擬10.6資源運輸 矩陣定理

描述 n<=300,給定有權邊,求生成樹大小和所有生成樹邊權乘積和。 要點 基爾霍夫矩陣: c [

JZOJ-senior-5878. NOIP2018提高模擬9.22電路圖 A

Time Limits: 1000 ms Memory Limits: 262144 KB Description nodgd 要畫一個電路圖。 這是一個很簡單的電路圖,所有的元件都是串聯關係,從整體

[jzoj 5770]2018提高模擬A8.6可愛精靈寶貝 (區間dp)

以及 stdin isdigit char spa ios 遺憾 etc 時間 傳送門 Description Branimirko是一個對可愛精靈寶貝十分癡迷的玩家。最近,他閑得沒事組織了一場捉精靈的遊戲。遊戲在一條街道上舉行,街道上一側有一排房子,從左到右房子標號由1到