BZOJ 1146: [CTSC2008]网络管理Network 【树上带修改主席树】

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100005
using namespace std;

int a[N], b[N], M, T[N], st, w[N], A[N], B[N], C[N];

struct Tr
{
    int c, ls, rs;
}tr[8000010];

int hash(int k)
{
    return lower_bound(b, b+M, k)-b;
}

int build(int l, int r)
{
    int nr = st++, mid = l+r>>1;
    tr[nr].c = 0;
    if (l < r)
    {
        tr[nr].ls = build(l, mid);
        tr[nr].rs = build(mid+1, r);
    }
    return nr;
}

int update(int l, int r, int pos, int val, int root)
{
    int nr = st++, mid = l+r>>1;
    tr[nr].c = tr[root].c+val;
    if (l < r)
    {
        if (pos <= mid) tr[nr].ls = update(l, mid, pos, val, tr[root].ls), tr[nr].rs = tr[root].rs;
        else tr[nr].rs = update(mid+1, r, pos, val, tr[root].rs), tr[nr].ls = tr[root].ls;
    }
    return nr;
}

int tot, dep[N*4], pos[N], t[N*4], dp[N*4][20], size, head[N], id;
int lq[N], rq[N];
bool vi[N];

struct E
{
    int v, ne;
    E(){}
    E(int _v, int _ne):v(_v), ne(_ne){}
}e[N*2];

void init()
{
     memset(vi, 0, sizeof(vi));
     memset(head, -1, sizeof(head));
     size = tot = st = id = 0;
}

void add(int u, int v)
{
     e[size] = E(v, head[u]);
     head[u] = size++;
}

void DP()
{
     int i, j;
     memset(dp, 0, sizeof(dp));
     for (j = 0;(1<<j) <= tot;j++)
     {
         for (i = 0;i + (1<<j) <= tot;i++)
         {
             if (j == 0) dp[i][j] = i;
             else
             {
                 if (dep[dp[i][j - 1]] < dep[dp[i + (1<<(j - 1))][j - 1]]) dp[i][j] = dp[i][j - 1];
                 else dp[i][j] = dp[i + (1<<(j - 1))][j - 1];
             }
         }
     }
}

int RMQ(int p1, int p2)
{
    int k = 0;
    while ((1<<k) <= p2 - p1 + 1) k++;k--;
    if (dep[dp[p1][k]] < dep[dp[p2 - (1<<k) + 1][k]])
       return t[dp[p1][k]];
    else return t[dp[p2 - (1<<k) + 1][k]];
}

int lac(int v1, int v2)
{
    if (pos[v1] < pos[v2]) return RMQ(pos[v1], pos[v2]);
    else return RMQ(pos[v2], pos[v1]);
}

int F[N];

void dfs(int u, int fa, int dfn)
{
     int i;
     if (!vi[u])
     {
        vi[u] = 1, lq[u] = ++id, F[u] = fa;
        T[u] = update(0, M-1, w[u-1], 1, T[fa]);
        pos[u] = tot;//第一次出现的时间
     }
     dep[tot] = dfn;//深度序列;
     t[tot++] = u;//欧拉序列;
     for (i = head[u];~i;i = e[i].ne)
     {
         if (vi[e[i].v]) continue;
         dfs(e[i].v, u, dfn + 1);
         dep[tot] = dfn;
         t[tot++] = u;
     }
     rq[u] = id+1;
     return;
}

int S[N], Ro[N*30], Lo[N*30];

int lb(int k){return k&(-k);}

void adds(int i, int k, int val, int n)
{
    while (i <= n)
    {
        S[i] = update(0, M-1, k, val, S[i]);
        i += lb(i);
    }
}

void get(int ro[], int x)
{
    ro[++ro[0]] = T[x];
    x = lq[x];
    while (x > 0) {ro[++ro[0]] = S[x]; x -= lb(x);}
}

void go(int ro[], int p)
{
    int i;
    for (i = 1;i <= ro[0];i++)
    {
        if (!p) ro[i] = tr[ro[i]].rs;
        else ro[i] = tr[ro[i]].ls;
    }
}

int query(int l, int r, int k)
{
    int i, sum = 0, mid = l+r>>1, tt = 0;
    if (l == r) return l;
    for (i = 1;i <= Ro[0];i++) sum += tr[tr[Ro[i]].rs].c, tt += tr[Ro[i]].c;
    for (i = 1;i <= Lo[0];i++) sum -= tr[tr[Lo[i]].rs].c, tt -= tr[Lo[i]].c;
    if (tt < k) return -1;
    if (sum >= k)
    {
        go(Ro, 0), go(Lo, 0);
        return query(mid+1, r, k);
    }
    else
    {
        go(Ro, 1), go(Lo, 1);
        return query(l, mid, k-sum);
    }
}

void cal(int l, int r, int k)
{
    int fa = lac(l, r);
    Ro[0] = Lo[0] = 0;
    get(Ro, l), get(Ro, r), get(Lo, fa), get(Lo, F[fa]);
    int re = query(0, M-1, k);
    if (re < 0) puts("invalid request!");
    else printf("%d\n", b[re]);
}

int main()
{
    int i, n, m, u, v, k;
    while (~scanf("%d%d", &n, &m))
    {
        init();M = 0;
        for (i = 0;i < n;i++) scanf("%d", &a[i]), b[M++] = a[i];
        for (i = 1;i < n;i++)
        {
            scanf("%d%d", &u, &v);
            add(u, v), add(v, u);
        }
        for (i = 0;i < m;i++)
        {
            scanf("%d%d%d", &A[i], &B[i], &C[i]);
            if (!A[i]) b[M++] = C[i];
        }
        memset(S, 0, sizeof(S));
        sort(b, b+M);
        M = unique(b, b+M)-b;
        T[0] = build(0, M-1);
        for (i = 0;i < n;i++) w[i] = hash(a[i]);
        dfs(1, 0, 0);
        DP();
        for (i = 0;i < m;i++)
        {
            k = A[i], u = B[i], v = C[i];
            if (k > 0) cal(u, v, k);
            else
            {
                v = hash(v);
                adds(lq[u], w[u-1], -1, n), adds(rq[u], w[u-1], 1, n);
                adds(lq[u], v, 1, n), adds(rq[u], v, -1, n);
                w[u-1] = v;
            }
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值