1. 程式人生 > >[Luogu P3302] [BZOJ 3123] [SDOI2013]森林

[Luogu P3302] [BZOJ 3123] [SDOI2013]森林

洛谷傳送門

題目描述

小Z有一片森林,含有NN個節點,每個節點上都有一個非負整數作為權值。初始的時候,森林中有MM條邊。

小Z希望執行TT個操作,操作有兩類:

  1. Q x y k查詢點xx到點yy路徑上所有的權值中,第kk小的權值是多少。此操作保證點xx和點yy連通,同時這兩個節點的路徑上至少有kk個點。
  2. L x y在點xx和點yy之間連線一條邊。保證完成此操作後,仍然是一片森林。

為了體現程式的線上性,我們把輸入資料進行了加密。設lastanslastans為程式上一次輸出的結果,初始的時候lastanslastans00

  • 對於一個輸入的操作Q x y k
    ,其真實操作為Q x^lastans y^lastans k^lastans
  • 對於一個輸入的操作L x y,其真實操作為L x^lastans y^lastans。其中^運算子表示異或,等價於pascal中的xorxor運算子。

請寫一個程式來幫助小Z完成這些操作。

對於所有的資料,n,m,T8104n,m,T\le 8*10^4.

輸入輸出格式

輸入格式:

第一行包含一個正整數testcasetestcase,表示當前測試資料的測試點編號。保證1testcase201\le testcase\le 20

第二行包含三個整數N

NMMTT,分別表示節點數、初始邊數、運算元。

第三行包含NN個非負整數表示 NN個節點上的權值。

接下來 MM行,每行包含兩個整數xxyy,表示初始的時候,點xx和點yy之間有一條無向邊。

接下來 TT行,每行描述一個操作,格式為Q x y k或者L x y,其含義見題目描述部分。

輸出格式:

對於每一個第一類操作,輸出一個非負整數表示答案。

輸入輸出樣例

輸入樣例#1:

1
8  4 8
1  1 2 2 3 3 4 4
4  7
1  8
2  4
2  1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6

輸出樣例#1:

2 
2
1
4
2

說明

對於第一個操作 Q 8 7 3,此時 lastans=0lastans=0,所以真實操作為Q 8^0 7^0 3^0,也即Q 8 7 3。點88到點77的路徑上一共有55點,其權值為4 1 1 2 4。 這些權值中,第三小的為 22,輸出 22lastanslastans變為22

對於第二個操作 Q 3 5 1 ,此時lastans=2lastans=2,所以真實操作為Q 3^2 5^2 1^2 ,也即Q 1 7 3。點11到點77的路徑上一共有44個點,其權值為1 1 2 4 。 這些權值中,第三小的為22,輸出22lastanslastans變為 22。之後的操作類似。

img

解題分析

首先我們看到了linklink操作, 想到LCTLCT, 但是鏈上kk大這種操作似乎LCTLCT不資瓷? 只好棄掉…

那麼什麼dsds資瓷這個操作? 顯然是主席樹。 合併怎麼辦?沒事我們還有啟發式合併, 無非加個loglog罷了。每次暴力DFSDFS重構聯通塊小的那個子樹, 用LCTLCT或倍增LCALCA維護聯通快內的LCALCA

總複雜度O(Nlog2(N))O(Nlog^2(N))

程式碼如下:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100050
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    for (; !isdigit(c); c = gc);
    for (;  isdigit(c); c = gc)
    x = (x << 1) + (x << 3) + c - 48;
}
struct Node1 {int son[2], fat, rev;} t[MX];
struct Node2 {int son[2], sum;} tree[MX * 800];
struct Edge {int to, nex;} edge[MX << 2];
int bel[MX], sta[MX], val[MX], cpy[MX], id[MX], head[MX], root[MX], siz[MX];
int dot, dif, q, kth, cnt, arr, lastans, line, top;
IN void add(R int from, R int to) {edge[++arr] = {to, head[from]}, head[from] = arr;}
int find(R int now) {return bel[now] == now ? now : bel[now] = find(bel[now]);}
namespace LCT
{
    #define dad t[now].fat
    #define ls t[now].son[0]
    #define rs t[now].son[1]
    IN bool get(R int now) {return t[dad].son[1] == now;}
    IN bool nroot(R int now) {return t[dad].son[1] == now || t[dad].son[0] == now;}
    IN void pushrev(R int now) {std::swap(ls, rs), t[now].rev ^= 1;}
    IN void pushdown(R int now) {if(t[now].rev) pushrev(ls), pushrev(rs), t[now].rev = 0;}
    IN void rotate(R int now)
    {
        R int fa = dad, grand = t[fa].fat;
        R bool dir = get(now);
        t[fa].son[dir] = t[now].son[dir ^ 1];
        t[t[now].son[dir ^ 1]].fat = fa;
        t[now].fat = grand;
        if(nroot(fa)) t[grand].son[get(fa)] = now;
        t[now].son[dir ^ 1] = fa;
        t[fa].fat = now;
    }
    IN void splay(R int now)
    {
        R int tmp = now, fa;
        sta[top = 1] = now;
        W (nroot(now)) sta[++top] = now = dad;
        W (top) pushdown(sta[top--]);
        now = tmp;
        W (nroot(now))
        {
            fa = dad;
            if(nroot(fa)) rotate(get(now) == get(fa) ? fa : now);
            rotate(now);
        }
    }
    IN int access(R int now)
    {
        R int x;
        for (x = 0; now; x = now, now = dad)
        splay(now), rs = x;
        return x;
    }
    IN void makeroot(R int x) {access(x), splay(x), pushrev(x);}
    IN int query(R int x, R int y) {access(x); return access(y);}
    IN void link(R int x, R int y) {makeroot(x); t[x].fat = y;}
    #undef dad
    #undef ls
    #undef rs
}
namespace PT
{
    #define ls tree[now].son[0]
    #define rs tree[now].son[1]
    void build(int &now, R int lef, R int rig)
    {
        now = ++cnt;
        if(lef == rig) return;
        int mid = lef + rig >> 1;
        build(ls, lef, mid), build(rs, mid + 1, rig);
    }
    void insert(int &now, R int pre, R int lef, R int rig, R int tar)
    {
        now = ++cnt; tree[now] = tree[pre]; tree[now].sum++;
        if(lef == rig) return;
        int mid = lef + rig >> 1;
        if(tar <= mid) insert(ls, tree[pre].son[0], lef, mid, tar);
        else insert(rs, tree[pre].son[1], mid + 1, rig, tar);
    }
    int query(R int a1, R int a2, R int b1, R int b2, R int lef, R int rig)
    {
        if(lef == rig) return cpy[lef];
        int lsum = tree[tree[a1].son[0]].sum + tree[tree[a2].son[0]].sum - tree[tree[b1].son[0]].sum - tree[tree[b2].son[0]].sum;
        int mid = lef + rig >> 1;
        if(lsum >= kth) return query(tree[a1].son[0], tree[a2].son[0], tree[b1].son[0], tree[b2].son[0], lef, mid);
        else return kth -= lsum, query(tree[a1].son[1], tree[a2].son[1], tree[b1].son[1], tree[b2].son[1], mid + 1, rig);
    }
    void DFS(R int now, R int fa)
    {
        insert(root[now], root[fa], 1, dif, id[now]);
        for (R int i = head[now]; i; i = edge[i].nex)
        {
            if(edge[i].to == fa) continue;
            DFS(edge[i].to, now);
        }
    }
    IN void merge(R int x, R int y)
    {
        int belx = find(x), bely = find(y);
        if(siz
            
           

相關推薦

[Luogu P3302] [BZOJ 3123] [SDOI2013]森林

洛谷傳送門 題目描述 小Z有一片森林,含有NNN個節點,每個節點上都有一個非負整數作為權值。初始的時候,森林中有MMM條邊。 小Z希望執行TTT個操作,操作有兩類: Q x y k查詢點xxx到點yyy路徑上所有的權值中,第kkk小的權值是多少。此操作保證點

BZOJ 3123 [Sdoi2013]森林

add str arp can test 森林 AD scan IT 題解: 啟發式合並主席樹 時間復雜度O(nlogn*logn) 空間復雜度O(nlogn*logn) Woc初始的時候也用了啟發式合並建圖,然後RE成翔了 一開始算錯了空間,下次註意 #include&

BZOJ-3123: [Sdoi2013]森林(主席樹 + LCA + 啟發式合併)

題目連結:https://www.lydsy.com/JudgeOnline/problem.php?id=3123 題目大意:給出一個有n個節點的森林,接下來有m次操作,每次操作有以下兩種: 1、Q x y k : 詢問節點 x 到節點 y 這條鏈上的點的第 k 大的權值是多少。

bzoj 3123: [Sdoi2013]森林 啟發式合併+可持久化線段樹

題意:給出一片森林,每個點有點權,要求資瓷兩個操作:詢問兩點間路徑的第k小點權;加一條邊 分析:如果沒有合併操作的話就是裸的可持久化線段樹啦。 但既然有合併操作那麼我們就每次把兩個塊的可持久化線段樹進行啟發式合併。 何為啟發式合併呢,其實就是暴力合併,把小一點的那棵樹上的

BZOJ3123: [Sdoi2013]森林

題解 ……………………………………………… 我莫不是一個智障吧 我把testdata的編號 當成資料組數讀進來 我簡直有毒 以為哪裡寫錯了自閉了好久 實際上這題很簡單,只要愉悅地開個啟發式合併,然後每次暴力修改一個點的根綴主席樹和倍增lca陣列就行 複雜度\(n \log^2 n\) 程式碼 #in

BZOJ 3123】 [Sdoi2013]森林 主席樹啟發式合並

name clas tree lca 部分 print 一切都 getch fine 我們直接按父子關系建主席樹,然後記錄倍增方便以後求LCA,同時用並查集維護根節點,而且還要記錄根節點對應的size,用來對其啟發式合並,然後每當我們合並的時候我們都要暴力拆小的一部分重復以

P3302 [SDOI2013]森林(主席樹+倍增或LCT維護LCA)

P3302 [SDOI2013]森林(主席樹+倍增或LCT維護LCA) 這道題要我們維護區間第K大,我們想到了主席樹。 而這道題要我們動態維護加邊,我們想到了 $LCT$ 。 對於樹上的一條路徑,我們可以使用差分的思想,設 $x$ 到 $y$ 的路徑, $x$ 與 $y$ 的最近公共祖先為 $lca$

BZOJ 3122 SDOI2013 隨機數生成器

color false std ros == d+ eal eof close 公式就不推了.hzwer上的很清楚. 值得註意的一點是,如果最後答案成0,需要加上mod.否則400ms wa. 1 #include<cstdio> 2 #incl

BZOJ 3130 [Sdoi2013]費用流

emp 流量 nbsp tdi hide nal for min ide 3130: [Sdoi2013]費用流 Description   Alice和Bob在圖論課程上學習了最大流和最小費用最大流的相關知識。最大流問題:給定一張有向圖表示運輸網絡,一個

BZOJ3123:[SDOI2013]森林——題解

debug 然而 sdoi2013 getch IT .org url () +++ http://www.lydsy.com/JudgeOnline/problem.php?id=3123 https://www.luogu.org/problemnew/show/P3

BZOJ 3131 SDOI2013 淘金 數位dp

AI 不難 amp 優先隊列 OS 正方 範圍 解決 names 原題鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=3131 題意沒什麽好概述的。。。。。 首先從題目對數的每一位進行相乘的操作以及N的範圍可以看

[SDOI2013]森林

nts nod front n) merge back getchar() let char [SDOI2013]森林 題目大意: 一個\(n(n\le8\times10^4)\)個點的森林,每個結點有一個權值\(w_i\)。\(q(q\le8\times10^4)\)次操

Luogu P3616 【富金森林公園】

我們首先考慮一塊石頭高度變化對每個高度的查詢的答案的影響,即我們要記錄,對於每個高度的查詢的答案所以要離散化高度(不然哪開的下陣列啊)不難發現,一次變化的對於不同高度的影響,對於一段連續高度是相同的即一次修改操作,對於一段連續高度的答案,影響相同,滿足區間修改性質就決定是你了,樹狀陣列具體來說,考慮修改位置修

BZOJ3123:[SDOI2013]森林

淺談主席樹:https://www.cnblogs.com/AKMer/p/9956734.html 題目傳送門:https://www.lydsy.com/JudgeOnline/problem.php?id=3123 如果是一棵樹,維護樹上路徑第\(k\)大,我們令\(rt[i]\)為加入\(i\)號

BZOJ3123: [Sdoi2013]森林(啟發式合併&主席樹)

3123: [Sdoi2013]森林 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4813  Solved: 1420[Submit][Status][Discuss]

BZOJ3123: [Sdoi2013]森林(啟發式合並&主席樹)

dfs sdoi2013 正整數 print != 數據 || b+ sin 3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4813 Solved: 1420[Submit][S

[Luogu P3206] [BZOJ 2001] [HNOI2010]城市建設

洛谷傳送門 BZOJ傳送門 描述 PS國是一個擁有諸多城市的大國,國王Louis為城市的交通建設可謂絞盡腦汁。Louis可以在某些城市之間修建道路,在不同的城市之間修建道路需要不同的花費。 Louis希望建造最少的道路使得國內所有的城市連通。但是由於某些因素,城市之間修建

[Luogu P3242] [BZOJ 4009] [HNOI2015]接水果

洛谷傳送門 BZOJ傳送門 題目描述 風見幽香非常喜歡玩一個叫做 osu!的遊戲,其中她最喜歡玩的模式就是接水果。由於她已經DT FC 了The big black, 她覺得這個遊戲太簡單了,於是發明了一個更加難的版本。 首先有一個地圖,是一棵由

[Luogu P4602] [BZOJ 5343] [CTSC2018]混合果汁

洛谷傳送門 BZOJ傳送門 題目描述 小 R 熱衷於做黑暗料理,尤其是混合果汁。 商店裡有 n n

[Luogu P2151] [BZOJ 1875] [SDOI2009]HH去散步

洛谷傳送門 BZOJ傳送門 題目描述 HH有個一成不變的習慣,喜歡飯後百步走。所謂百步走,就是散步,就是在一定的時間 內,走過一定的距離。 但是同時HH又是個喜歡變化的人,所以他不會立刻沿著剛剛走來的路走回。 又因為HH是個喜歡變化的人,所以他每天走過的路徑都不完全一樣,他想