洛谷 P2146 NOI2015 軟體包管理器

2022-03-15 16:16:42 字數 1748 閱讀 3429

題解原發於我的blog

首先,很明顯這是一道樹鏈剖分的題。

注意到乙個軟體只會以來乙個軟體,並且不會出現環,所以每次都可以連一條\((x\ ,\ i)\)的邊。

當安裝乙個軟體時,就把\((1\ ,\ x)\)的路徑上所有的點的轉態變為\(1\)

但解除安裝乙個軟體時,就把\(x\)及它的所有的子樹變為\(0\)

線段樹維護即可

推薦一道樹鏈剖分的好題【模板】樹鏈剖分

做完這道題就可以差不多學完所有關於樹鏈剖分的芝士

最後貼上**知道你們只看這個:

#include #include using namespace std;

template inline void read(t &x)

while (s >= '0' && s <= '9')

if (f)

x = (~x) + 1;

}#define re register

#define ls (k << 1)

#define rs (k << 1 | 1)

const int n = 1e5 + 10, m = 2e5 + 10, t = 4e5 + 10;

struct edge

edge[m];

int num_edge, head[n];

struct tree

tree[t];

char s[110];

int n, q, cnt;

int idx[n], rk[n], dep[n], fa[n], top[n], size[n], son[n]; //rk[i]其實並沒有什麼用這只是我的習慣

inline void add_edge(int from, int to)

inline void dfs1(int u, int f)

}inline void dfs2(int u, int tp)

}inline void pushdown(int k)

}inline void build(int k, int l, int r)

int mid = l + r >> 1;

build(ls, l, mid);

build(rs, mid + 1, r);

}inline void update1(int k, int l, int r, int val)

int mid = (tree[k].l + tree[k].r) >> 1;

pushdown(k);

if (l <= mid)

update1(ls, l, r, val);

if (mid < r)

update1(rs, l, r, val);

tree[k].sum = tree[ls].sum + tree[rs].sum;

}inline void update2(int x, int y)

if (dep[x] > dep[y])

swap(x, y);

update1(1, idx[x], idx[y], 1);

}int main()

dfs1(1, 0);

dfs2(1, 1);

build(1, 1, n);

read(q);

for (re int i = 1, before, x; i <= q; ++i)

else if (s[0] == 'u')

}return 0;

}

馬蜂差評

洛谷 P2146 NOI2015 軟體包管理器

如果乙個軟體被解除安裝,那答案就是它所有已安裝的子孫的個數 如果安裝,就是它到根的鏈上沒安裝的個數.注意修改lazy的時候 1 include2 include3 include4 include5 6using namespace std 78 int n,head 100001 rk 10000...

P2146 NOI2015 軟體包管理器

很好的樹剖板子題 操作一 求點x到0的最短路徑 經過的結點個數 路徑上已安裝的軟體包的總個數,同時將經過的路徑上的所有點標記為已安裝。操作二 將子樹代表的那段存安裝包個數的區間清空 或者是說將其sum值賦值為0 此處為了實現標記已安裝和清空,我們用了乙個標記add add i 1 線段樹上的點i及其...

P2146 NOI2015 軟體包管理器

輸入格式 從檔案manager.in中讀入資料。輸入檔案的第1行包含1個整數n,表示軟體包的總數。軟體包從0開始編號。隨後一行包含n 1個整數,相鄰整數之間用單個空格隔開,分別表示1,2,3,n 2,n 1號軟體包依賴的軟體包的編號。接下來一行包含1個整數q,表示詢問的總數。之後q行,每行1個詢問。...