[BZOJ1146][CTSC2008]网络管理Network

[CTSC2008]网络管理Network

Description
M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门。为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络。该网络的结构由N个路由器和N-1条高速光缆组成。每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络。该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信。 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略。但是由于路由器老化,在这些路由器上进行数据交换会带来很大的延迟。而两个路由器之间的通信延迟时间则与这两个路由器通信路径上所有路由器中最大的交换延迟时间有关。作为M公司网络部门的一名实习员工,现在要求你编写一个简单的程序来监视公司的网络状况。该程序能够随时更新网络状况的变化信息(路由器数据交换延迟时间的变化),并且根据询问给出两个路由器通信路径上延迟第k大的路由器的延迟时间。【任务】 你的程序从输入文件中读入N个路由器和N-1条光缆的连接信息,每个路由器初始的数据交换延迟时间Ti,以及Q条询问(或状态改变)的信息。并依次处理这Q条询问信息,它们可能是: 1. 由于更新了设备,或者设备出现新的故障,使得某个路由器的数据交换延迟时间发生了变化。 2. 查询某两个路由器a和b之间的路径上延迟第k大的路由器的延迟时间。
Input
第一行为两个整数N和Q,分别表示路由器总数和询问的总数。第二行有N个整数,第i个数表示编号为i的路由器初始的数据延迟时间Ti。紧接着N-1行,每行包含两个整数x和y。表示有一条光缆连接路由器x和路由器y。紧接着是Q行,每行三个整数k、a、b。如果k=0,则表示路由器a的状态发生了变化,它的数据交换延迟时间由Ta变为b。如果k>0,则表示询问a到b的路径上所经过的所有路由器(包括a和b)中延迟第k大的路由器的延迟时间。注意a可以等于b,此时路径上只有一个路由器。
Output
对于每一个第二种询问(k>0),输出一行。包含一个整数为相应的延迟时间。如果路径上的路由器不足k个,则输出信息“invalid request!”(全部小写不包含引号,两个单词之间有一个空格)。
Sample Input
5 5
5 1 2 3 4
3 1
2 1
4 3
5 3
2 4 5
0 1 2
2 2 3
2 1 4
3 3 5
Sample Output
3
2
2
invalid request!
HINT
10% 测试数据满足N<=8000,Q<=3000,
40% 测试数据满足所有询问中1<=K<=5 。即路由器的延迟时间不会发生变化。
100% 测试数据满足N,Q<=80000,任意一个路由器在任何时刻都满足延迟时间小于10^8。对于所有询问满足0<=K<=N 。

Solution
树状数组套动态开点的线段树(防止MLE)
利用dfs序,将修改转化为区间修改,利用树状数组维护差分的前缀和

Code

//%czgj
#include <bits/stdc++.h>
using namespace std;

#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define MS(_) memset(_, 0, sizeof(_))
#define MP make_pair
#define PB push_back
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define OK puts("OK");
typedef long long ll;
typedef pair<int, int> PII;
template<typename T> inline void read(T &x){
    x = 0; T f = 1; char ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
    while (isdigit(ch))  { x = x * 10 + ch - '0'; ch = getchar(); }
    x *= f;
}

const int N = 80010;
const int M = 9000010; 
int n, m, rt[2][N], last[N], a[N], lca[N], lst[N<<1], root[N], K[N], A[N], B[N], l[N], r[N], f[N], fa[N];
int sum[M], lc[M], rc[M];
int tot, top, timeclk, cnt, sz;
bool vis[N];
vector<PII> query[N];
struct Node{int to, nxt;}edge[N<<1];

inline void addedge(int u, int v){
    edge[++top].to = v; edge[top].nxt = last[u]; last[u] = top;
    edge[++top].to = u; edge[top].nxt = last[v]; last[v] = top;
}
inline int find(int k) {return fa[k] = fa[k]==k ? k : find(fa[k]);}
inline void dfs(int x){ 
    l[fa[x] = x] = ++timeclk;
    for (int p = last[x]; p; p = edge[p].nxt) 
        if (edge[p].to != f[x]){
            f[edge[p].to] = x; dfs(edge[p].to); fa[edge[p].to] = x;
        } 
    r[x] = timeclk; 
    vis[x] = 1;
    for (int i = 0; i < query[x].size(); i++)
        if (vis[query[x][i].first]) lca[query[x][i].second] = find(query[x][i].first);
}

inline void mdf(int &rt, int tl, int tr, int p, int dt){
    if (!rt) rt = ++sz; sum[rt] += dt;
    if (tl == tr) return;
    int mid = tl+tr >> 1;
    if (p <= mid) mdf(lc[rt], tl, mid, p, dt);
    else mdf(rc[rt], mid+1, tr, p, dt);
}
inline void mdf(int x, int p, int dt){
    for(; x <= n; x += (x&-x)) mdf(root[x], 1, tot, p, dt);
}
inline void modify(int l, int r, int p, int dt){
    mdf(l, p, dt); mdf(r+1, p, -dt);    
}
inline void GETROOT(int x, int p){
    for (; x > 0; x -= (x&-x)) rt[p][++rt[p][0]] = root[x];  
}
inline int qryKth(int k){ int l = 1, r = tot, mid, res, tmp;
    while (l < r){
        mid = l+r >> 1; res = 0; tmp = 0;
        rep(i, 1, rt[0][0]) res -= sum[rc[rt[0][i]]], tmp -= sum[rt[0][i]];
        rep(i, 1, rt[1][0]) res += sum[rc[rt[1][i]]], tmp += sum[rt[1][i]];
        if (tmp < k) return -1;
        if (k <= res){
            rep(i, 1, rt[0][0]) rt[0][i] = rc[rt[0][i]];
            rep(i, 1, rt[1][0]) rt[1][i] = rc[rt[1][i]];
            l = mid+1;
        }else{
            rep(i, 1, rt[0][0]) rt[0][i] = lc[rt[0][i]];
            rep(i, 1, rt[1][0]) rt[1][i] = lc[rt[1][i]];
            r = mid; k -= res;
        }
    }
    return l;
}
int main(){
    read(n); read(m);
    rep(i, 1, n) read(a[i]), lst[++tot] = a[i];
    rep(i, 1, n-1){ int u, v;
        read(u); read(v); addedge(u, v);
    }
    rep(i, 1, m){
        read(K[i]); read(A[i]); read(B[i]);
        if (!K[i]) lst[++tot] = B[i];
        else query[A[i]].PB(MP(B[i], i)), query[B[i]].PB(MP(A[i],i));
    }
    sort(lst+1, lst+1+tot);
    tot = unique(lst+1, lst+1+tot) - lst - 1;
    rep(i, 1, n) a[i] = lower_bound(lst+1, lst+1+tot, a[i]) - lst;
    dfs(1);

    rep(i, 1, n) modify(l[i], r[i], a[i], 1);
    rep(i, 1, m){
        if (!K[i]){
            modify(l[A[i]], r[A[i]], a[A[i]], -1); 
            a[A[i]] = lower_bound(lst+1, lst+1+tot, B[i]) - lst;
            modify(l[A[i]], r[A[i]], a[A[i]], 1);
        }else{ int x = A[i], y = B[i], z = lca[i];
            rt[0][0] = rt[1][0] = 0;
            GETROOT(l[x], 1); GETROOT(l[y], 1);
            GETROOT(l[z], 0); GETROOT(l[f[z]], 0);
            int ans = qryKth(K[i]); 
            if (ans < 0) puts("invalid request!");
            else printf("%d\n", lst[ans]);
        }   
    }
    return 0;
}

你可能感兴趣的:(树套树)