[CTSC2008]網絡管理Network【樹狀數組+主席樹】

題目鏈接


題意:有一棵N個點的樹,每個點有對應的權值,現在有這樣的操作,“0 a b”將a點的權值改成爲b,“k a b”詢問a到b的鏈上第k大的權值是幾。

  我們可以用dfs序的樹上差分的方式來解決這個問題,可以發現,求u到v的信息,其實就是求u到lca和v到lca的合併,所以我們得想辦法把這條鏈上的第k大給處理出來,這時候可以使用主席樹來進行操作,我們不妨給點u賦值的時候,賦值給dfn[u]~dfn[u]+siz[u]-1,是這棵子樹上的所有的點都被給予了這個值,不妨在dfn[u]位置“+1”,dfn[u]+siz[u]的位置上“-1”,用dfs序的方式將他們放到了一條鏈上去進行差分。

  但是現在有了修改的操作,我們改變一個值的時候,實際上會對他的所有的子樹造成影響,所以我們改成給原來的每個點都是一棵主席樹,我們將原來的dfs序成的序列拿出來,看成一維軸的形式,然後,就是對這個一維的軸進行操作了。

  那麼,我們可以利用樹狀數組,對這個前綴差分來進行操作,不妨在dfn[u]的點處先減去原來的點權的貢獻,再換上新的點權,然後同理不要忘記dfn[u]+siz[u]這個位置的操作。

#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 eps 1e-8
#define INF 0x3f3f3f3f
#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
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 8e4 + 7;
int N, Q, head[maxN], cnt, a[maxN], Lsan[maxN << 1], _UP;
vector<int> bin;
struct Eddge
{
    int nex, to;
    Eddge(int a=-1, int b=0):nex(a), to(b) {}
} edge[maxN << 1];
inline void addEddge(int u, int v)
{
    edge[cnt] = Eddge(head[u], v);
    head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
struct Question
{
    int k, a, b;
    void In() { scanf("%d%d%d", &k, &a, &b); }
} ques[maxN];
int siz[maxN], fa[maxN], deep[maxN], Wson[maxN];
void dfs_1(int u, int father)
{
    siz[u] = 1; fa[u] = father; deep[u] = deep[father] + 1;
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == father) continue;
        dfs_1(v, u);
        if(siz[v] > siz[Wson[u]]) Wson[u] = v;
    }
}
int top[maxN], dfn[maxN], rid[maxN], tim, End_tim[maxN];
void dfs_2(int u, int topy)
{
    top[u] = topy; dfn[u] = ++tim; rid[tim] = u;
    if(Wson[u]) dfs_2(Wson[u], topy);
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == fa[u] || v == Wson[u]) continue;
        dfs_2(v, v);
    }
    End_tim[u] = tim;
}
int _LCA(int u, int v)
{
    while(top[u] ^ top[v])
    {
        if(deep[top[u]] < deep[top[v]]) swap(u, v);
        u = fa[top[u]];
    }
    if(deep[u] > deep[v]) swap(u, v);
    return u;
}
const int max_T = maxN * 400;
int t[max_T], lc[max_T], rc[max_T], tot, root[maxN];
void Insert(int &now, int old, int l, int r, int pos, int val)
{
    if(!now) now = ++tot;
    t[now] = t[old] + val; lc[now] = lc[old]; rc[now] = rc[old];
    if(l == r) return;
    int mid = HalF;
    if(pos <= mid) Insert(lc[now], lc[old], l, mid, pos, val);
    else Insert(rc[now], rc[old], mid + 1, r, pos, val);
}
void Pre_update(int x, int pos, int val)
{
    while(x <= N)
    {
        Insert(root[x], root[x], 1, _UP, pos, val);
        x += lowbit(x);
    }
}
int tmp_1[maxN], tmp_2[maxN], t1, t2;
int query(int l, int r, int kth)
{
    int mid, sum;
    while(l ^ r)
    {
        mid = HalF; sum = 0;
        for(int i=1; i<=t1; i++) sum += t[rc[tmp_1[i]]];
        for(int i=1; i<=t2; i++) sum -= t[rc[tmp_2[i]]];
        if(sum >= kth)
        {
            for(int i=1; i<=t1; i++) tmp_1[i] = rc[tmp_1[i]];
            for(int i=1; i<=t2; i++) tmp_2[i] = rc[tmp_2[i]];
            l = mid + 1;
        }
        else
        {
            for(int i=1; i<=t1; i++) tmp_1[i] = lc[tmp_1[i]];
            for(int i=1; i<=t2; i++) tmp_2[i] = lc[tmp_2[i]];
            r = mid;
            kth -= sum;
        }
    }
    return l;
}
int Pre_Query(int u, int v, int kth)
{
    t1 = t2 = 0;
    for(int i=dfn[u]; i; i -= lowbit(i)) tmp_1[++t1] = root[i];
    for(int i=dfn[v]; i; i -= lowbit(i)) tmp_1[++t1] = root[i];
    int lca = _LCA(u, v);
    if(deep[u] + deep[v] - deep[lca] - deep[fa[lca]] < kth) return -1;
    for(int i=dfn[lca]; i; i -= lowbit(i)) tmp_2[++t2] = root[i];
    for(int i=dfn[fa[lca]]; i; i -= lowbit(i)) tmp_2[++t2] = root[i];
    return query(1, _UP, kth);
}
void dfs_3(int u, int ff)
{
    Pre_update(dfn[u], a[u], 1);
    Pre_update(End_tim[u] + 1, a[u], -1);
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == ff) continue;
        dfs_3(v, u);
    }
}
inline void init()
{
    cnt = 0; _UP = N; tim = 0; tot = 0;
    for(int i=1; i<=N; i++) head[i] = -1;
}
int main()
{
    scanf("%d%d", &N, &Q);
    for(int i=1; i<=N; i++) { scanf("%d", &a[i]); Lsan[i] = a[i]; }
    init();
    for(int i=1, u, v; i<N; i++)
    {
        scanf("%d%d", &u, &v);
        _add(u, v);
    }
    for(int i=1; i<=Q; i++) { ques[i].In(); if(!ques[i].k) Lsan[++_UP] = ques[i].b; }
    sort(Lsan + 1, Lsan + _UP + 1);
    _UP = (int)(unique(Lsan + 1, Lsan + _UP + 1) - Lsan - 1);
    for(int i=1; i<=N; i++) a[i] = (int)(lower_bound(Lsan + 1, Lsan + _UP + 1, a[i]) - Lsan);
    for(int i=1; i<=Q; i++) if(!ques[i].k) ques[i].b = (int)(lower_bound(Lsan + 1, Lsan + _UP + 1, ques[i].b) - Lsan);
    dfs_1(1, 0);
    dfs_2(1, 1);
    dfs_3(1, 0);
    int ans;
    for(int i=1; i<=Q; i++)
    {
        if(ques[i].k == 0)
        {
            Pre_update(dfn[ques[i].a], a[ques[i].a], -1);
            Pre_update(End_tim[ques[i].a] + 1, a[ques[i].a], 1);
            Pre_update(dfn[ques[i].a], ques[i].b, 1);
            Pre_update(End_tim[ques[i].a] + 1, ques[i].b, -1);
            a[ques[i].a] = ques[i].b;
        }
        else
        {
            ans = Pre_Query(ques[i].a, ques[i].b, ques[i].k);
            if(~ans)
            {
                printf("%d\n", Lsan[ans]);
            }
            else
            {
                printf("invalid request!\n");
            }
        }
    }
    return 0;
}

 

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