BZOJ3720 Gty的妹子樹Solution

題目大意:

維護一棵初始有n個節點的有根樹(根節點爲1),樹上節點編號爲1-n,每個點有一個權值wi。


支持以下操作:

0 u x          詢問以u爲根的子樹中,嚴格大於x的值的個數。(u^=lastans,x^=lastans)

1 u x          把u節點的權值改成x。(u^=lastans,x^=lastans)

2 u x          添加一個編號爲"當前樹中節點數+1"的節點,其父節點爲u,其權值爲x。(u^=lastans,x^=lastans)

最開始時lastans=0。

思路:開始看到詢問是與子樹有關的,又要支持動態加點,想到動態維護dfs序,然而一個區間第k大就讓splay滾粗了。

然後離線構樹也不行。

那麼覺得不可做,想到分塊亂搞。

然而這是一棵樹,如何進行樹上分塊呢?


我們用一次dfs過程將樹分塊。

首先,定義根節點在塊1中,塊1的size爲1.

從根節點向下dfs,對於當前點x,依次遍歷其兒子,若遍歷到兒子son時x所在的塊的size小於Maxsize,則將son加入x所在的塊,x所在的塊的size+1.

否則,建立一個新塊,使son加入這個新塊,新塊的size+1.

每遍歷到一個兒子就向下dfs.


然後我們記錄兩個圖,一個是原來的樹,一個是塊與塊之間形成的圖,只需要在每次產生新塊的時候加一條邊即可。

不難發現,塊與塊之間事實上形成的也是樹形結構。

我們再對於每一個塊記錄下塊內所有的權值,並排序。


對於詢問,我們從當前節點向下dfs,若遇到一個兒子不屬於其所在的塊,則轉到塊與塊之間形成的樹向下搜索,每遇到一個塊就在塊裏二分找答案。如果兒子依舊屬於這個塊,那就直接看一下他和x的大小關係即可。若令Maxsize=sqrt(n),這樣的複雜度是O(sqrt(n)log(sqrt(n))).

對於加入新點,我們直接在其父親所在的塊中加入一個點即可,需要暴力修改權值的有序序列,複雜度O(sqrt(n)).當然如果父親所在的塊size達到了MAxsize,就新建一個一個點的新塊。

如果修改權值,就直接在這個點所在的塊的權值序列中暴力刪除,插入即可,時間複雜度O(sqrt(n)).


事實上可能取Maxsize=sqrt(n)logn快一些?不過我T了。。。


Code:

#include <cmath>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
 
inline int getc() {
    static const int L = 1 << 15;
    static char buf[L], *S = buf, *T = buf;
    if (S == T) {
        T = (S = buf) + fread(buf, 1, L, stdin);
        if (S == T)
            return EOF;
    }
    return *S++;
}
inline int getint() {
    int c;
    while(!isdigit(c = getc()));
    int tmp = c - '0';
    while(isdigit(c = getc()))
        tmp = (tmp << 1) + (tmp << 3) + c - '0';
    return tmp;
}
 
#define N 30010
#define M 30010
#define Num 5010
#define Size 5010
 
struct Graph {
    int head[N + M], next[(N + M)<<1], end[(N + M)<<1], ind;
    void reset() {
        ind = 0;
        memset(head, -1, sizeof(head));
    }
    void addedge(int a, int b) {
        int q = ind++;
        end[q] = b;
        next[q] = head[a];
        head[a] = q;
    }
    void make(int a, int b) {
        addedge(a, b);
        addedge(b, a);
    }
}G;
 
struct Lump {
    int head[Num], next[Num << 1], end[Num << 1], ind;
    void reset() {
        ind = 0;
        memset(head, -1, sizeof(head));
    }
    void addedge(int a, int b) {
        int q = ind++;
        end[q] = b;
        next[q] = head[a];
        head[a] = q;
    }
    void make(int a, int b) {
        addedge(a, b);
        addedge(b, a);
    }
}Lumps;
 
int w[N + M];
 
int per, size[Num], sav[Num][Size], belong[N + M], cnt, pa[N + M];
void dfs(int x, int fa) {
    for(int j = G.head[x]; j != -1; j = G.next[j]) {
        if (G.end[j] == fa)
            continue;
        pa[G.end[j]] = x;
        if (size[belong[x]] == per) {
            belong[G.end[j]] = ++cnt, sav[cnt][++size[cnt]] = w[G.end[j]];
            Lumps.make(cnt, belong[x]);
        }
        else
            belong[G.end[j]] = belong[x], sav[belong[x]][++size[belong[x]]] = w[G.end[j]];
        dfs(G.end[j], x);
    }
}
 
inline int ask_Big(int ins, int x) {
    sav[ins][size[ins] + 1] = 1 << 30;
    int L = 1, R = size[ins] + 1, mid;
    while(L < R) {
        mid = (L + R) >> 1;
        if (sav[ins][mid] > x)
            R = mid;
        else
            L = mid + 1;
    }
    return size[ins] + 1 - L;
}
inline int ask_Lump(int x, int fa, int val) {
    int res = ask_Big(x, val);
    for(int j = Lumps.head[x]; j != -1; j = Lumps.next[j]) {
        if (Lumps.end[j] != fa)
            res += ask_Lump(Lumps.end[j], x, val);
    }
    return res;
}
inline int ask(int x, int fa, int val) {
    int res = w[x] > val ? 1 : 0;
    for(int j = G.head[x]; j != -1; j = G.next[j]) {
        if (G.end[j] != fa) {
            if (belong[G.end[j]] != belong[x])
                res += ask_Lump(belong[G.end[j]], belong[x], val);
            else
                res += ask(G.end[j], x, val);
        }
    }
    return res;
}
 
void remove(int ins, int val) {
    int i, j;
    for(i = 1; i <= size[ins]; ++i)
        if (sav[ins][i] == val)
            break;
    --size[ins];
    for(j = i; j <= size[ins]; ++j)
        sav[ins][j] = sav[ins][j + 1];
}
void insert(int ins, int val) {
    int i, j;
    for(i = 1; i <= size[ins]; ++i)
        if (sav[ins][i] > val)
            break;
    ++size[ins];
    for(j = size[ins]; j > i; --j)
        sav[ins][j] = sav[ins][j - 1];
    sav[ins][i] = val;
}
 
int main() {
    int n = getint();
     
    register int i;
    int a, b;
    G.reset();
    for(i = 1; i < n; ++i) {
        a = getint(), b = getint();
        G.make(a, b);
    }
     
    for(i = 1; i <= n; ++i)
        w[i] = getint();
     
    per = (int)sqrt(n * log(n)/log(2));
     
    Lumps.reset();
    belong[1] = size[++cnt] = 1, sav[cnt][1] = w[1];
    dfs(1, -1);
     
    for(i = 1; i <= cnt; ++i)
        sort(sav[i] + 1, sav[i] + size[i] + 1);
     
    int Q, ope, lastans = 0;
    Q = getint();
    while(Q--) {
        ope = getint(), a = getint(), b = getint();
        a ^= lastans;
        b ^= lastans;
        if (!ope)
            printf("%d\n", lastans = ask(a, pa[a], b));
        else if (ope == 1) {
            remove(belong[a], w[a]);
            insert(belong[a], w[a] = b);
        }
        else {
            w[++n] = b;
            pa[n] = a;
            if (size[belong[a]] == per) {
                belong[n] = ++cnt;
                size[cnt] = 1;
                sav[cnt][1] = w[n];
                G.make(a, n);
                Lumps.make(belong[a], cnt);
            }
            else {
                belong[n] = belong[a];
                insert(belong[a], w[n]);
                G.make(a, n);
            }
        }
    }
     
    return 0;
}


發佈了54 篇原創文章 · 獲贊 3 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章