QTREE4 - Query on a tree IV【動態點分治/點分樹】

題目鏈接 SP2666 QTREE4 - Query on a tree IV


給定一棵 n 個點的帶邊權的樹,點從 1 到 n 編號。每個點可能有兩種顏色:黑或白。我們定義 dist(a,b) 爲點 a 至點 b 路徑上的權值之和。

一開始所有的點都是白色的。

要求作以下操作:

C a 將點 a 的顏色反轉。(黑變白,白變黑)

A 詢問 dist(a,b) 的最大值。a,b 點都必須爲白色(a 與 b 可以相同),顯然如果樹上仍存在白點,查詢得到的值一定是個非負數。

特別地,如果 A 操作時樹上沒有白點,輸出 They have disappeared.

對於100% 的數據,N \leq 100000,Q \leq 100000,-10^3 \leq c \leq 10^3。


  這道題跟[ZJOI2007]捉迷藏【動態點分治】在做法上有異曲同工之處,只是邊不再是單位長度,而是給出了對應的邊長,同時邊長可以爲負數。

  這道題用動態點分治的做法,容易被卡時限,可以考慮使用快讀來加速讀入,因爲輸入真的很大。

  然後,正如我們所知道的,我們不妨考慮經過一個點的最遠到達和次遠到達,來確定直徑的長度,然後,也有可能是到自己就是作爲一個次遠到達來完成這個。

  所以,每一個結點要用一個堆來記錄它的子結點到它的父節點的距離值。

這裏講幾個細節上的東西:

  • 處理都是在點分樹上進行處理的;
  • 只有對下面結點的距離數量大於等於2的時候,纔有可能產生答案;
  • 我們在更新答案之前,要刪除舊的答案的影響;
  • 不要忘記形成的直徑可能是自己和自己所能到達的最遠距離;
  • 最初給ans要push一個0,因爲答案不允許是負數;
  • 同時,如果黑點的數量==N的時候,不要忘記按要求輸出。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define Big_INF 0x3f3f3f3f3f3f3f3f
#define eps 1e-6
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
inline int read()
{
    int x=0, r = 1; char c = getchar();
    while (c < '0' || c > '9') { if(c == '-') r = -1; c = getchar(); }
    while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * r;
}
const int maxN = 2e5 + 7;
int N, Q, head[maxN], cnt, LOG_2[maxN << 1];
struct Eddge
{
    int nex, to; int val;
    Eddge(int a=-1, int b=0, int c=0):nex(a), to(b), val(c) {}
} edge[maxN << 1];
inline void addEddge(int u, int v, int w)
{
    edge[cnt] = Eddge(head[u], v, w);
    head[u] = cnt++;
}
inline void _add(int u, int v, int w) { addEddge(u, v, w); addEddge(v, u, w); }
struct Grand_Father
{
    int deep[maxN], euler[maxN << 1], Esiz, rid[maxN]; int dis[maxN];
    void dfs(int u, int fa)
    {
        deep[u] = deep[fa] + 1; rid[u] = Esiz + 1;
        for(int i=head[u], v; ~i; i=edge[i].nex)
        {
            v = edge[i].to;
            if(v == fa) continue;
            dis[v] = dis[u] + edge[i].val;
            euler[++Esiz] = u;
            dfs(v, u);
        }
        euler[++Esiz] = u;
    }
    int mn[maxN << 1][20];
    inline void RMQ_Init()
    {
        for(int i=1; i<=Esiz; i++) mn[i][0] = euler[i];
        for(int j=1; (1 << j) <= Esiz; j++)
        {
            for(int i=1; i + (1 << j) - 1 <= Esiz; i++)
            {
                if(deep[mn[i][j - 1]] < deep[mn[i + (1 << (j - 1))][j - 1]]) mn[i][j] = mn[i][j - 1];
                else mn[i][j] = mn[i + (1 << (j - 1))][j - 1];
            }
        }
    }
    inline int Rmq(int l, int r)
    {
        int det = r - l + 1, kk = LOG_2[det];
        if(deep[mn[l][kk]] <= deep[mn[r - (1 << kk) + 1][kk]]) return mn[l][kk];
        else return mn[r - (1 << kk) + 1][kk];
    }
    inline int _LCA(int u, int v)
    {
        int l = rid[u], r = rid[v];
        if(l > r) swap(l, r);
        return Rmq(l, r);
    }
    inline int _Dis(int u, int v)
    {
        int lca = _LCA(u, v);
        return dis[u] + dis[v] - 2 * dis[lca];
    }
} A_lca;
struct heap
{
    priority_queue<int> Que, Del;
    inline bool empty()
    {
        while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
        return Que.empty();
    }
    inline void push(int val) { Que.push(val); }
    inline void clear(int val) { Del.push(val); }
    inline int size() { return (int)(Que.size() - Del.size()); }
    inline int top()
    {
        while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
        return Que.top();
    }
    inline void pop()
    {
        while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
        Que.pop();
    }
    inline int Fir_Sec()
    {
        int s[2] = {0};
        if(!empty()) s[0] = top();
        pop();
        if(!empty()) s[1] = top();
        push(s[0]);
        return s[0] + s[1];
    }
} ans, s[maxN][2];
int black_num = 0;
int siz[maxN], all, son[maxN], maxx, root, father[maxN];
bool vis[maxN] = {false};
void findroot(int u, int fa)
{
    siz[u] = 1; son[u] = 0;
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(vis[v] || v == fa) continue;
        findroot(v, u);
        siz[u] += siz[v];
        son[u] = max(son[u], siz[v]);
    }
    son[u] = max(son[u], all - siz[u]);
    if(son[u] < maxx) { maxx = son[u]; root = u; }
}
void Get_dis(int u, int fa)
{
    s[root][0].push(A_lca._Dis(u, father[root]));
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(vis[v] || v == fa) continue;
        Get_dis(v, u);
    }
}
void Divide(int u)
{
    vis[u] = true;
    if(father[u]) Get_dis(u, 0);
    int totsiz = all;
    for(int i=head[u], v, rt; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(vis[v]) continue;
        all = siz[v] > siz[u] ? totsiz - siz[u] : siz[v];
        maxx = INF;
        findroot(v, 0);
        father[root] = u;
        rt = root;
        Divide(root);
        s[u][1].push(s[rt][0].top());
    }
    s[u][1].push(0);
    if(s[u][1].size() >= 2) ans.push(s[u][1].Fir_Sec());
}
bool black[maxN] = {false};
void turn(int u)
{
    int p, cop_u = u; int df, das;
    black[u] ^= 1;
    if(black[u])
    {
        black_num ++;
        if(s[u][1].size() >= 2) ans.clear(s[u][1].Fir_Sec());
        s[u][1].clear(0);
        if(s[u][1].size() >= 2) ans.push(s[u][1].Fir_Sec());
        p = father[u];
        while(p)
        {
            df = A_lca._Dis(cop_u, p);
            if(s[p][1].size() >= 2)
            {
                das = s[p][1].Fir_Sec();
                ans.clear(das);
            }
            s[p][1].clear(s[u][0].top());
            s[u][0].clear(df);
            if(!s[u][0].empty()) s[p][1].push(s[u][0].top());
            if(s[p][1].size() >= 2)
            {
                das = s[p][1].Fir_Sec();
                ans.push(das);
            }
            u = p;
            p = father[u];
        }
    }
    else
    {
        black_num --;
        if(s[u][1].size() >= 2) ans.clear(s[u][1].Fir_Sec());
        s[u][1].push(0);
        if(s[u][1].size() >= 2) ans.push(s[u][1].Fir_Sec());
        p = father[u];
        while(p)
        {
            df = A_lca._Dis(cop_u, p);
            if(s[p][1].size() >= 2)
            {
                das = s[p][1].Fir_Sec();
                ans.clear(das);
            }
            if(!s[u][0].empty()) s[p][1].clear(s[u][0].top());
            s[u][0].push(df);
            s[p][1].push(s[u][0].top());
            if(s[p][1].size() >= 2)
            {
                das = s[p][1].Fir_Sec();
                ans.push(das);
            }
            u = p;
            p = father[u];
        }
    }
}
inline void init()
{
    cnt = 0; ans.push(0);
    for(int i=1; i<=N; i++) head[i] = -1;
    for(int i = 1, j = 2, k = 0; i<=(N << 1); i++)
    {
        if(i == j) { j <<= 1; k ++; }
        LOG_2[i] = k;
    }
}
int main()
{
    N = read();
    init();
    for(int i=1, u, v, w; i<N; i++)
    {
        u = read(); v = read(); w = read();
        _add(u, v, w);
    }
    A_lca.dfs(1, 0);
    A_lca.RMQ_Init();
    all = N; maxx = INF;
    findroot(1, 0);
    Divide(root);
    scanf("%d", &Q);
    char op[3]; int x;
    while(Q--)
    {
        scanf("%s", op);
        if(op[0] == 'A')
        {
            if(black_num == N) printf("They have disappeared.\n");
            else printf("%d\n", ans.top());
        }
        else
        {
            x = read();
            turn(x);
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章