zoukankan      html  css  js  c++  java
  • 【BZOJ1146】【树链剖分+平衡树】网络管理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^8。对于所有询问满足0<=K<=N 。

    Source

    CTSC2008
    【分析】
    居然1A了,天不负有心人啊.....写了1个半小时TAT
    裸的树上带修改第k大,用树链剖分转成线段树,在每个线段树里面维护一个平衡树。
    查找的时候先二分答案,再按照树链剖分的方式找就行了。
    发现动态内存分配还是蛮好的,均摊分析,空间复杂度不会爆。
      1 /*
      2 唐代韦庄
      3 《菩萨蛮·劝君今夜须沈醉》
      4 劝君今夜须沉醉,尊前莫话明朝事。珍重主人心,酒深情亦深。
      5 须愁春漏短,莫诉金杯满。遇酒且呵呵,人生能几何! 
      6 */
      7 #include <iostream>
      8 #include <cstdio>
      9 #include <algorithm>
     10 #include <cstring>
     11 #include <vector>
     12 #include <utility>
     13 #include <iomanip>
     14 #include <string>
     15 #include <cmath>
     16 #include <queue>
     17 #include <assert.h>
     18 #include <map>
     19 #include <ctime>
     20 #include <cstdlib>
     21 #include <stack>
     22 #include <set> 
     23 #define LOCAL
     24 const int INF = 0x7fffffff;
     25 const int MAXN = 80000  + 10;
     26 const int maxnode = 20000 * 2 + 200000 * 20;
     27 const int MAXM = 1000000 + 10;
     28 const int MAX = 100000000;
     29 using namespace std;
     30 struct Treap{
     31        int val;
     32        int fix, siz;
     33        Treap *ch[2];
     34        
     35        void update(){
     36             siz = 1;
     37             if (ch[0] != NULL) siz += ch[0]->siz;
     38             if (ch[1] != NULL) siz += ch[1]->siz;
     39        }
     40 };
     41 //将t的d儿子换到t 
     42 void rotate(Treap *&t, int d){
     43      Treap *p = t->ch[d];
     44      t->ch[d] = p->ch[d ^ 1];
     45      t->update();
     46      p->ch[d ^ 1] = t;
     47      p->update();
     48      t = p; 
     49      return;
     50 }
     51 Treap *NEW(int val){
     52       Treap *t = new Treap;
     53       t->fix = rand();
     54       t->val = val;
     55       t->siz = 1;
     56       t->ch[0] = t->ch[1] = NULL;
     57       return t;
     58 }
     59 void insert(Treap *&t, int val){
     60      if (t == NULL){
     61         t = NEW(val);
     62         return;
     63      }
     64      int d = (val >= t->val);
     65      insert(t->ch[d], val);
     66      if (t->ch[d]->fix > t->fix) rotate(t, d);
     67      t->update();
     68 }
     69 int size(Treap *&t) {return (t == NULL) ? 0: t->siz;}
     70 //统计比val大的数量,包括val! 
     71 int get(Treap *&t, int val){
     72     if (t == NULL) return 0;
     73     //右边都比他大.. 
     74     if (val <= t->val) return size(t->ch[1]) + 1 + get(t->ch[0], val);
     75     else return get(t->ch[1], val); 
     76 }
     77 void erase(Treap *&t, int x){
     78      int d;
     79      if (x == t->val) d = -1;
     80      else d = (x > t->val);//随意删除一个就行了
     81      
     82      if (d == -1){
     83         Treap *tmp = t;
     84         if (t->ch[0] == NULL){//左儿子为0那么就变成右儿子 
     85            t = t->ch[1];
     86            delete tmp;
     87         }else if (t->ch[1] == NULL){
     88            t = t->ch[0];
     89            delete tmp;
     90         }else{//还没到叶子转下去 
     91            int f = (t->ch[1]->fix > t->ch[0]->fix);
     92            rotate(t, f);
     93            erase(t->ch[f ^ 1], x);//注意转到另一边了 
     94         }
     95      }else erase(t->ch[d], x);
     96      if (t != NULL) t->update();
     97 }
     98 
     99 //------------------------以上为Treap------------------//
    100  
    101 struct Node{//线段树的节点
    102        int l, r;
    103        Treap *t;//注意这个里面用动态内存分配...无奈. 
    104        Node *ch[2];
    105 }*root, mem[MAXN * 2];
    106 int n, q;//点数和询问总述数量 
    107 int head[MAXN * 2], to[MAXN * 2];//vector会爆? 
    108 int M, next[MAXN * 2], fa[MAXN];
    109 int Time, data[MAXN], son[MAXN], siz[MAXN], pos[MAXN];//时间轴 
    110 int top[MAXN], tot, dep[MAXN];
    111 
    112 void addEdge(int u, int v){
    113      to[M] = v;
    114      next[M]= head[u];
    115      head[u] = M++;
    116 }
    117 void dfs_1(int u){
    118      son[u] = 0;
    119      siz[u] = 1;
    120      for (int i = head[u];i != -1; i = next[i]){
    121          int v = to[i];
    122          if (v == fa[u]) continue;
    123          fa[v] = u;
    124          dep[v] = dep[u] + 1;
    125          dfs_1(v);
    126          siz[u] += siz[v];
    127          if (siz[v] > siz[son[u]]) son[u] = v;
    128      }
    129 }
    130 void dfs_2(int u, int top_node){
    131      pos[u] = ++Time;
    132      top[u] = top_node;
    133      if (son[u]) dfs_2(son[u], top_node);
    134      for (int i = head[u]; i != -1; i = next[i]){
    135          int v = to[i];
    136          if (v == fa[u] || v == son[u]) continue;
    137          dfs_2(v, v); 
    138      } 
    139 }
    140 Node *NEW(int l, int r){
    141      Node *p = &mem[tot++];
    142      p->l = l;
    143      p->r = r;
    144      p->t = NULL;//p里面的treap
    145      p->ch[0] = p->ch[1] = NULL;
    146      return p; 
    147 }
    148 void build(Node *&t, int l, int r){
    149      if (t == NULL){
    150         t = NEW(l, r);
    151      }
    152      if (l == r) return;
    153      int mid = (l + r) >> 1;
    154      build(t->ch[0], l, mid);
    155      build(t->ch[1], mid + 1, r);
    156 }
    157 //居然是单点修改OAO 
    158 //将l位置的路由器延迟时间由x变为y 
    159 void change(Node *&p, int l, int x, int y){
    160      if (p->l == l && p->r == l){
    161         if (x != INF) erase(p->t, x);//为INF的时候就是单纯的插入 
    162         insert(p->t, y);
    163         return;
    164      }
    165      if (x != INF) erase(p->t, x);
    166      insert(p->t, y);
    167      
    168      int mid = (p->l + p->r) >> 1;
    169      if (l <= mid) change(p->ch[0], l, x, y);
    170      else change(p->ch[1], l, x, y); 
    171 }
    172 //表示在l,r这一段内比val大的数的个数 
    173 int query(Node *&p, int l, int r, int val){
    174     if (l <= p->l && p->r <= r) return get(p->t, val);
    175     int mid = (p->l + p->r) >> 1;
    176     int sum = 0;
    177     if (l <= mid) sum += query(p->ch[0], l, r, val);
    178     if (r > mid) sum += query(p->ch[1], l, r, val); 
    179     return sum;
    180 }
    181 void init(){
    182      memset(head, -1, sizeof(head));
    183      memset(dep, 0, sizeof(dep));//表示根到自己不包含根的节点数量 
    184      siz[0] = fa[1] = 0;
    185      M = Time = 0;
    186      
    187      scanf("%d%d", &n, &q);
    188      for (int i = 1; i <= n; i++) scanf("%d", &data[i]);
    189      for (int i = 1; i < n; i++){
    190          int u, v;
    191          scanf("%d%d", &u, &v);
    192          addEdge(u, v);
    193          addEdge(v, u);
    194      }
    195      dfs_1(1);
    196      dfs_2(1, 1);
    197      build(root, 1, Time);
    198      for (int i = 1; i <= n; i++) 
    199      change(root, pos[i], INF, data[i]);
    200 }
    201 //返回在lr区间内比x大的数个数 
    202 int check(int l, int r, int x){
    203     int sum = 0;
    204     while (top[l] != top[r]){
    205           //保证永远矮的往上爬 
    206           if (dep[top[l]] < dep[top[r]]) swap(l, r);
    207           sum += query(root, pos[top[l]], pos[l], x);
    208           l = fa[top[l]];
    209     }
    210     //显然l应该高一点 
    211     if (dep[l] > dep[r]) swap(l, r);
    212     sum += query(root, pos[l], pos[r], x);
    213     return sum;
    214 }
    215 int query(int L, int R, int k){
    216     //首先二分最大值k
    217     int Ans, l = -MAX, r = MAX;
    218     while (l <= r){
    219           int mid = (l + r) >> 1;
    220           if (mid == 3)
    221           printf("");
    222           if (check(L, R, mid) >= k) Ans = mid, l = mid + 1;
    223           else r = mid - 1; 
    224     }
    225     //printf("%d", check(L, R, 3));
    226     return Ans;
    227 }
    228 int search(int l, int r){
    229     int sum = 0;
    230     while (top[l] != top[r]){
    231           if (dep[top[l]] < dep[top[r]]) swap(l, r);
    232           sum += dep[l] - dep[top[l]] + 1;
    233           l = fa[top[l]];
    234     }
    235     //dep[r]大 
    236     if (dep[l] > dep[r]) swap(l, r);
    237     sum += dep[r] - dep[l] + 1;
    238     return sum;
    239 } 
    240 void work(){
    241      for (int i = 1; i <= q; i++){
    242         
    243          int l, r, k;
    244          scanf("%d%d%d", &k, &l, &r); 
    245          //if (i == 5)
    246          //printf("%d", k);
    247          if (k == 0){//修改操作 
    248             change(root, pos[l], data[l], r);
    249             data[l] = r;
    250          }else{//查询
    251             int num = search(l, r);//查询l到r之间的节点个数 
    252             if (k > num) {printf("invalid request!
    ");continue;}
    253             printf("%d
    ", query(l, r, k));
    254          }
    255      }
    256 }
    257 void debug(){
    258      /*Treap *root = NULL;
    259      insert(root, 2);
    260      printf("%d", get(root, 2));*/ 
    261      //printf("%d", search(4, 2));
    262      //for (int i = 1; i <= 5; i++) printf("%d
    ", pos[i]);
    263      //printf("%d", query(root, 2, 3, 3));
    264 }
    265 
    266 int main(){
    267     //srand(time(0));
    268     
    269     init();
    270     work();
    271     //debug();
    272     return 0;
    273 }
    View Code
     
  • 相关阅读:
    最长公共上升子序列
    最长公共子序列
    3847: Mowing the Lawn (单调队列)
    A/B(扩展欧几里得)
    One Person Game(扩展欧几里得)
    Substring with Concatenation of All Words, 返回字符串中包含字符串数组所有字符串元素连接而成的字串的位置
    Divide two numbers,两数相除求商,不能用乘法,除法,取模运算
    Merge k Sorted Lists, k路归并
    二路归并排序,利用递归,时间复杂度o(nlgn)
    StrStr,判断一个字符串是不是另一个字符串的字串,并返回子串的位置
  • 原文地址:https://www.cnblogs.com/hoskey/p/4345254.html
Copyright © 2011-2022 走看看