zoukankan      html  css  js  c++  java
  • BZOJ3083: 遥远的国度

    3083: 遥远的国度

    Time Limit: 10 Sec  Memory Limit: 1280 MB
    Submit: 4198  Solved: 1109
    [Submit][Status][Discuss]

    Description

    描述
    zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。

    问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成 了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有 一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的 话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但 zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

    Input

    第1行两个整数n m,代表城市个数和操作数。
    第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
    第n+1行,有n个整数,代表所有点的初始防御值。
    第n+2行一个整数 id,代表初始的首都为id。
    第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数 p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。

    Output


    对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

    Sample Input

    3 7
    1 2
    1 3
    1 2 3
    1
    3 1
    2 1 1 6
    3 1
    2 2 2 5
    3 1
    2 3 3 4
    3 1

    Sample Output

    1
    2
    3
    4
    提示
    对于20%的数据,n<=1000 m<=1000。
    对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。
    对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。
    对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。
    对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。

    HINT

    Source

    树剖序列其实就是一个dfs序,用树剖的方法查询/修改路径,dfs序的方法查询/修改子树

    换根操作:手画一颗比较复杂的树,设原根节点为root,换根后为now,会发现只有查询root->now这条路径上的子树时,换根操作才会带来影响。

    设查询子树的根节点为u,u在root->now的路径上,整棵树集合为G,以u在root->now的路径上的儿子为根的子树为G',查询范围其实是G - G',这样就把dfs序分成了2~3块,有一块不需要查,查剩余1~2块即可

    dfs序处理子树区间l,r时,跟着树剖的第二遍dfs顺便做就好了

    倍增手残写错卡了半天。。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <algorithm>
      6 #include <queue>
      7 #include <vector>
      8 #define min(a, b) ((a) < (b) ? (a) : (b))
      9 #define max(a, b) ((a) > (b) ? (a) : (b))
     10 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
     11 inline void swap(int &a, int &b)
     12 {
     13     int tmp = a;a = b;b = tmp;
     14 }
     15 inline void read(int &x)
     16 {
     17     x = 0;char ch = getchar(), c = ch;
     18     while(ch < '0' || ch > '9') c = ch, ch = getchar();
     19     while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
     20     if(c == '-') x = -x;
     21 }
     22 
     23 const int INF = 0x3f3f3f3f;
     24 const int MAXN = 500000 + 10;
     25 
     26 struct Edge
     27 {
     28     int u,v,nxt;
     29     Edge(int _u, int _v, int _nxt){u = _u;v = _v;nxt = _nxt;}
     30     Edge(){} 
     31 }edge[MAXN << 1];
     32 int head[MAXN], cnt;
     33 inline void insert(int a, int b)
     34 {
     35     edge[++cnt] = Edge(a,b,head[a]);
     36     head[a] = cnt;
     37 }
     38 int root,now,top[MAXN],w[MAXN],fa[MAXN],rank[MAXN],tim,deep[MAXN],tid[MAXN],size[MAXN],son[MAXN],n,q,l[MAXN],r[MAXN],p[MAXN][30],M;
     39 
     40 void dfs1(int u)
     41 {
     42     size[u] = 1;
     43     for(register int pos = head[u];pos;pos = edge[pos].nxt)
     44     {
     45         int v = edge[pos].v;
     46         if(v == fa[u]) continue;
     47         fa[v] = u;p[v][0] = u;deep[v] = deep[u] + 1;dfs1(v);
     48         size[u] += size[v];
     49         if(son[u] == -1 || size[v] > size[son[u]]) son[u] = v;
     50     }
     51 }
     52 void dfs2(int u, int tp)
     53 {
     54     tid[u] = ++ tim, rank[tim] = u;top[u] = tp;l[u] = r[u] = tim;
     55     if(son[u] == -1) return;
     56     dfs2(son[u], tp);
     57     for(register int pos = head[u];pos;pos = edge[pos].nxt)
     58     {
     59         int v = edge[pos].v;
     60         if(v != fa[u] && v != son[u]) dfs2(v, v);
     61     }
     62     r[u] = tim;
     63 }
     64 struct Node
     65 {
     66     int l,r,mi,lazy;
     67     Node(){l = r = mi = lazy = 0;}
     68 }node[MAXN << 2];
     69 void pushup(Node &a, Node &l, Node &r)
     70 {
     71     if(a.lazy)
     72     {
     73         l.mi = r.mi = a.lazy;
     74         l.lazy = r.lazy = a.lazy;
     75         a.lazy = 0;
     76     }
     77 }
     78 Node merge(Node &a, Node &b)
     79 {
     80     if(a.l == 0) return b;
     81     if(b.l == 0) return a;
     82     Node re;re.l = a.l, re.r = b.r;
     83     re.mi = min(a.mi, b.mi);
     84     return re;
     85 }
     86 void build(int o = 1, int l = 1, int r = n)
     87 {
     88     node[o].l = l, node[o].r = r;
     89     if(l == r)
     90     {
     91         node[o].mi = w[rank[l]];
     92         return;
     93     }
     94     int mid = (node[o].l + node[o].r) >> 1;
     95     build(o << 1, l, mid);
     96     build(o << 1 | 1, mid + 1, r);
     97     node[o] = merge(node[o << 1], node[o << 1 | 1]);
     98     return;
     99 }
    100 void modify(int ll, int rr, int k, int o = 1)
    101 {
    102     pushup(node[o], node[o << 1], node[o << 1 | 1]);
    103     if(ll <= node[o].l && rr >= node[o].r)
    104     {
    105         node[o].mi = k;
    106         node[o].lazy = k;
    107         return;
    108     }
    109     int mid = (node[o].l + node[o].r) >> 1;
    110     if(mid >= ll) modify(ll, rr, k, o << 1);
    111     if(mid < rr) modify(ll, rr, k, o << 1 | 1);
    112     node[o] = merge(node[o << 1], node[o << 1 | 1]);
    113     return;
    114 }
    115 Node ask(int ll, int rr, int o = 1)
    116 {
    117     pushup(node[o], node[o << 1], node[o << 1 | 1]);
    118     if(ll <= node[o].l && rr >= node[o].r) return node[o];
    119     int mid = (node[o].l + node[o].r) >> 1;
    120     Node a,b;
    121     if(mid >= ll) a = ask(ll, rr, o << 1);
    122     if(mid < rr) b = ask(ll, rr, o << 1 | 1);
    123     if(a.l == 0) return b;
    124     else if(b.l == 0) return a;
    125     return merge(a, b);
    126 }
    127 
    128 void yuchuli()
    129 {
    130     M = 0;
    131     while((1 << M) <= n) ++ M;
    132     -- M;
    133     for(register int i = 1;i <= M;++ i)
    134         for(register int j = 1;j <= n;++ j)
    135             p[j][i] = p[p[j][i - 1]][i - 1];
    136 } 
    137 
    138 int LCA(int u, int v)
    139 {
    140     if(deep[u] < deep[v]) swap(u, v);
    141     for(register int i = M;i >= 0;-- i)
    142         if(deep[u] - (1 << i) >= deep[v])
    143             u = p[u][i];
    144     if(u == v) return u;
    145     for(register int i = M;i >= 0;-- i)
    146         if(p[u][i] != p[v][i])
    147             u = p[u][i], v = p[v][i];
    148     return fa[u];
    149 }
    150 
    151 //找根为now的情况下x子树最小 
    152 Node find(int x)
    153 {
    154     Node re;
    155     if(now == root)
    156         re = ask(l[x], r[x]);
    157     else
    158     {
    159         int lca = LCA(x, now);
    160         if(lca != x) re = ask(l[x], r[x]);
    161         else
    162         {
    163             int tmp = now;
    164             for(register int i = M;i >= 0;-- i)
    165                 if(deep[p[tmp][i]] > deep[x])
    166                     tmp = p[tmp][i];
    167             Node tmp1,tmp2;    
    168             if(l[tmp] - 1 >= 1)    tmp1 = ask(1, l[tmp] - 1);
    169             if(r[tmp] + 1 <= n) tmp2 = ask(r[tmp] + 1, n);
    170             re = merge(tmp1, tmp2);
    171         }
    172     }
    173     return re;
    174 }
    175 
    176 //修改路径 
    177 void change(int x, int y, int k)
    178 {
    179     int f1 = top[x], f2 = top[y];
    180     while(f1 != f2)
    181     {
    182         if(deep[f1] < deep[f2]) swap(f1, f2), swap(x, y);
    183         modify(tid[f1], tid[x], k);
    184         x = fa[f1], f1 = top[x];
    185     }
    186     if(deep[x] > deep[y]) swap(x, y);
    187     modify(tid[x], tid[y], k);
    188 }
    189 
    190 int main()
    191 {
    192     memset(son, -1, sizeof(son));
    193     read(n), read(q);
    194     for(register int i = 1;i < n;++ i)
    195     {
    196         int tmp1,tmp2;read(tmp1), read(tmp2);
    197         insert(tmp1, tmp2), insert(tmp2, tmp1);
    198     }
    199     for(register int i = 1;i <= n;++ i) read(w[i]);
    200     read(root);now = root;
    201     dfs1(root);
    202     dfs2(root, root);
    203     build();
    204     yuchuli();
    205     for(register int i = 1;i <= q;++ i)
    206     {
    207         int opt;read(opt);
    208         if(opt == 1) read(now);
    209         else if(opt == 2)
    210         {
    211             int tmp1, tmp2, tmp3;
    212             read(tmp1), read(tmp2), read(tmp3);
    213             change(tmp1, tmp2, tmp3);
    214         }
    215         else
    216         {
    217             read(opt);
    218             Node tmp = find(opt);
    219             printf("%d
    ", tmp.mi);
    220         }
    221     }
    222     return 0;
    223 }
    BZOJ3083
  • 相关阅读:
    NOIP 2011 DAY 2
    NOIP 2011 DAY 1
    扩展欧几里得算法(exgcd)
    中国剩余定理
    线性同余方程的求解
    乘法逆元
    poj 1845 Sumdiv(约数和,乘法逆元)
    欧拉-费马小定理定理(证明及推论)
    求解范围中 gcd(a,b)== prime 的有序对数
    KindEditor解决上传视频不能在手机端显示的问题
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/8306835.html
Copyright © 2011-2022 走看看