zoukankan      html  css  js  c++  java
  • 树链剖分

    1、hdu 3966 Aragorn's Story

      题意:敌人有n个帐篷,每个帐篷有初始人数,两两之间只有一条路径。现在进行q次操作,可以把c1到c2路径上的所有帐篷人数都加上或减去一个值,或者询问某个帐篷当前人数。

      思路:树链剖分模板题,线段树,点权,区间更新,单点查询。

      1 #include<iostream>
      2 #include<cstring>
      3 using namespace std;
      4 const int maxn = 50000 + 10;
      5 
      6 /*-------树链剖分·启-------*/
      7 
      8 int siz[maxn];//size[i]:以i为根的子树结点个数
      9 int top[maxn];//保存结点i所在链的顶端结点
     10 int son[maxn];//保存i的重儿子
     11 int dep[maxn];//保存结点i的层次(深度)
     12 int father[maxn];//保存结点i的父亲结点
     13 int nid[maxn];//保存树节点剖分后的对应新编号
     14 int oid[maxn];//保存新编号对应在剖分的树中的结点(与nid相反)
     15 int cnt = 0;//重编号
     16 int val[maxn];//结点值
     17 struct EDGE
     18 {
     19     int from, to, next;
     20     EDGE(int ff = 0, int tt = 0, int nn = 0) :from(ff), to(tt), next(nn) {}
     21 }edge[maxn * 2];
     22 int Head[maxn], totedge = 0;
     23 void addEdge(int from, int to)
     24 {
     25     edge[totedge] = EDGE(from, to, Head[from]);
     26     Head[from] = totedge++;
     27     edge[totedge] = EDGE(to, from, Head[to]);
     28     Head[to] = totedge++;
     29 }
     30 void INIT()
     31 {
     32     memset(Head, -1, sizeof(Head));
     33     totedge = 0;
     34 
     35     memset(son, -1, sizeof(son));
     36     memset(siz, 0, sizeof(siz));
     37     memset(father, 0, sizeof(father));
     38     memset(top, 0, sizeof(top));
     39     memset(dep, 0, sizeof(dep));
     40     cnt = 0;
     41 }
     42 
     43 void dfs1(int u, int fa, int layer)
     44 {
     45     dep[u] = layer;
     46     father[u] = fa;
     47     siz[u] = 1;
     48     for (int i = Head[u]; i != -1; i = edge[i].next)
     49     {
     50         int v = edge[i].to;
     51         if (v != fa)
     52         {
     53             dfs1(v, u, layer + 1);
     54             siz[u] += siz[v];
     55             if (son[u] == -1 || siz[v] > siz[son[u]])
     56             {
     57                 son[u] = v;
     58             }
     59         }
     60     }
     61 }
     62 
     63 void dfs2(int u, int Hson)
     64 {//Hson,重儿子
     65     top[u] = Hson;
     66     nid[u] = ++cnt;
     67     oid[cnt] = u;
     68     if (son[u] == -1) return;
     69     dfs2(son[u], Hson);//先将当前重链重编号
     70     for (int i = Head[u]; i != -1; i = edge[i].next)
     71     {//对不在重链上的点,自己作为子树的重链起点重编号
     72         int v = edge[i].to;
     73         if (v != son[u] && v != father[u]) dfs2(v, v);
     74     }
     75 }
     76 /*-------线段树·启————*/
     77 struct treenode
     78 {
     79     int l, r;
     80     long long v, tmp;
     81     treenode(int ll = 0, int rr = 0, long long vv = 0, long long tt = 0) :l(ll), r(rr), v(vv), tmp(tt) {}
     82 }tree[maxn * 4];
     83 
     84 void BuildTree(int root, int l, int r)
     85 {
     86     tree[root].l = l, tree[root].r = r;
     87     tree[root].tmp = 0;
     88     if (l == r)
     89     {
     90         tree[root].v = val[oid[l]];
     91         return;
     92     }
     93     int mid = (l + r) / 2;
     94     BuildTree(root * 2, l, mid);
     95     BuildTree(root * 2 + 1, mid + 1, r);
     96     tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v;
     97 }
     98 void Pushdown(int root)
     99 {
    100     int lson = root * 2, rson = root * 2 + 1;
    101     if (tree[root].tmp)
    102     {
    103         tree[lson].v += (tree[lson].r - tree[lson].l + 1)*tree[root].tmp;
    104         tree[rson].v += (tree[rson].r - tree[rson].l + 1)*tree[root].tmp;
    105         tree[lson].tmp += tree[root].tmp;
    106         tree[rson].tmp += tree[root].tmp;
    107         tree[root].tmp = 0;
    108     }
    109 }
    110 void PushUp(int root)
    111 {
    112     tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v;
    113 }
    114 void Update(int root, int l, int r, int add)
    115 {
    116     if (tree[root].r<l || tree[root].l>r) return;
    117     if (l <= tree[root].l&&tree[root].r <= r)
    118     {
    119         tree[root].tmp += add;
    120         tree[root].v += add * (tree[root].r - tree[root].l + 1);
    121         return;
    122     }
    123     Pushdown(root);
    124     int mid = (tree[root].r + tree[root].l) / 2;
    125     if (l <= mid)Update(root * 2, l, r, add);
    126     if (r>mid)Update(root * 2 + 1, l, r, add);
    127     PushUp(root);
    128 }
    129 
    130 long long Query(int root, int l, int r)
    131 {
    132     if (tree[root].r<l || tree[root].l>r) return 0;
    133     if (l <= tree[root].l&&tree[root].r <= r)
    134     {
    135         return tree[root].v;
    136     }
    137     Pushdown(root);
    138     long long tsum = Query(root * 2, l, r) + Query(root * 2 + 1, l, r);
    139     PushUp(root);
    140     return tsum;
    141 }
    142 /*-------线段树·终————*/
    143 
    144 long long Query_length(int x, int y)
    145 {//查询结点x到y路径上所有结点值之和
    146     long long ans = 0;
    147     int fx = top[x], fy = top[y];
    148     while (fx != fy)
    149     {
    150         if (dep[fx] >= dep[fy])
    151         {
    152             ans += Query(1, nid[fx], nid[x]);//在一条重链上的值用线段树维护、查询
    153             x = father[fx];
    154             fx = top[x];
    155         }
    156         else
    157         {
    158             ans += Query(1, nid[fy], nid[y]);
    159             y = father[fy];
    160             fy = top[y];
    161         }
    162     }
    163     //此时x与y已经在一条重链上,而重链上的编号都是连续的
    164     if (x != y)
    165     {
    166         if (nid[x] < nid[y])
    167         {
    168             ans += Query(1, nid[x], nid[y]);
    169         }
    170         else
    171         {
    172             ans += Query(1, nid[y], nid[x]);
    173         }
    174     }
    175     else ans += Query(1, nid[x], nid[y]);
    176     return ans;
    177 }
    178 
    179 void Update_path(int x, int y, int add)
    180 {//将x到y路径上所有结点的值都加上add
    181     int fx = top[x], fy = top[y];
    182     while (fx != fy)
    183     {
    184         if (dep[fx] >= dep[fy])
    185         {
    186             Update(1, nid[fx], nid[x], add);
    187             x = father[fx];
    188             fx = top[x];
    189         }
    190         else
    191         {
    192             Update(1, nid[fy], nid[y], add);
    193             y = father[fy];
    194             fy = top[y];
    195         }
    196     }
    197     if (x != y)
    198     {
    199         if (nid[x] < nid[y]) Update(1, nid[x], nid[y], add);
    200         else Update(1, nid[y], nid[x], add);
    201     }
    202     else Update(1, nid[x], nid[y], add);
    203 }
    204 /*-------树链剖分·终-------*/
    205 
    206 int main()
    207 {
    208     int n, m, p;
    209     while (~scanf("%d%d%d", &n, &m, &p))
    210     {
    211         INIT();
    212         for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
    213         for (int i = 1; i <= m; i++)
    214         {
    215             int from, to;
    216             scanf("%d%d", &from, &to);
    217             addEdge(from, to);
    218         }
    219         dfs1(1, 1, 1);
    220         dfs2(1, 1);
    221         BuildTree(1, 1, n);
    222         char s[10];
    223         for (int i = 1; i <= p; i++)
    224         {
    225             scanf("%s", s);
    226             int c1, c2, k, c;
    227             switch (s[0])
    228             {
    229             case 'I':
    230                 scanf("%d%d%d", &c1, &c2, &k);
    231                 Update_path(c1, c2, k);
    232                 break;
    233             case 'D':
    234                 scanf("%d%d%d", &c1, &c2, &k);
    235                 Update_path(c1, c2, -k);
    236                 break;
    237             case 'Q':
    238                 scanf("%d", &c);
    239                 printf("%lld
    ", Query(1, nid[c], nid[c]));
    240                 break;
    241             }
    242         }
    243     }
    244     return 0;
    245 }
    View Code

    2、HYSBZ - 2243 染色

      题意:

    给定一棵有n个节点的无根树和m个操作,操作有2类:
    1、将节点a到节点b路径上所有点都染成颜色c;
    2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
    如“112221”由3段组成:“11”、“222”和“1”。
    请你写一个程序依次完成这m个操作。
      思路:
    树链剖分+线段树,点权,区间更新+区间查询,分段。线段树应当记录[l,r]中颜色段数量以及左右边界颜色。
      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 using namespace std;
      5 const int maxn = 100000+ 10;
      6 
      7 /*-------树链剖分·启-------*/
      8 
      9 int siz[maxn];//size[i]:以i为根的子树结点个数
     10 int top[maxn];//保存结点i所在链的顶端结点
     11 int son[maxn];//保存i的重儿子
     12 int dep[maxn];//保存结点i的层次(深度)
     13 int father[maxn];//保存结点i的父亲结点
     14 int nid[maxn];//保存树节点剖分后的对应新编号
     15 int oid[maxn];//保存新编号对应在剖分的树中的结点(与nid相反)
     16 int cnt = 0;//重编号
     17 int val[maxn];//结点值
     18 struct EDGE
     19 {
     20     int from, to, next;
     21     EDGE(int ff = 0, int tt = 0, int nn = 0) :from(ff), to(tt), next(nn) {}
     22 }edge[maxn * 2];
     23 int Head[maxn], totedge = 0;
     24 void addEdge(int from, int to)
     25 {
     26     edge[totedge] = EDGE(from, to, Head[from]);
     27     Head[from] = totedge++;
     28     edge[totedge] = EDGE(to, from, Head[to]);
     29     Head[to] = totedge++;
     30 }
     31 void INIT()
     32 {
     33     memset(Head, -1, sizeof(Head));
     34     totedge = 0;
     35 
     36     memset(son, -1, sizeof(son));
     37     cnt = 0;
     38 }
     39 
     40 void dfs1(int u, int fa, int layer)
     41 {
     42     dep[u] = layer;
     43     father[u] = fa;
     44     siz[u] = 1;
     45     for (int i = Head[u]; i != -1; i = edge[i].next)
     46     {
     47         int v = edge[i].to;
     48         if (v != fa)
     49         {
     50             dfs1(v, u, layer + 1);
     51             siz[u] += siz[v];
     52             if (son[u] == -1 || siz[v] > siz[son[u]])
     53             {
     54                 son[u] = v;
     55             }
     56         }
     57     }
     58 }
     59 
     60 void dfs2(int u, int Hson)
     61 {//Hson,重儿子
     62     top[u] = Hson;
     63     nid[u] = ++cnt;
     64     oid[cnt] = u;
     65     if (son[u] == -1) return;
     66     dfs2(son[u], Hson);//先将当前重链重编号
     67     for (int i = Head[u]; i != -1; i = edge[i].next)
     68     {//对不在重链上的点,自己作为子树的重链起点重编号
     69         int v = edge[i].to;
     70         if (v != son[u] && v != father[u]) dfs2(v, v);
     71     }
     72 }
     73 /*-------线段树·启————*/
     74 struct treenode
     75 {
     76     int l, r;
     77     int v, l_color, r_color;
     78     int delay;
     79     treenode(int ll = 0, int rr = 0,int vv = 0, int lc = 0,int rc=0,int dd=0) :l(ll), r(rr), v(vv),l_color(lc),r_color(rc),delay(dd){}
     80 }tree[maxn * 4];
     81 
     82 void PushUp(int root)
     83 {
     84     int lson = root * 2, rson = root * 2 + 1;
     85     tree[root].v = tree[lson].v + tree[rson].v;
     86     if (tree[lson].r_color == tree[rson].l_color) tree[root].v--;
     87     tree[root].l_color = tree[lson].l_color, tree[root].r_color = tree[rson].r_color;
     88 }
     89 
     90 void BuildTree(int root, int l, int r)
     91 {
     92     tree[root].l = l, tree[root].r = r;
     93     tree[root].delay = 0;
     94     if (l == r)
     95     {
     96         tree[root].v = 1;
     97         tree[root].l_color=tree[root].r_color = val[oid[l]];
     98         return;
     99     }
    100     int mid = (l + r) / 2;
    101     BuildTree(root * 2, l, mid);
    102     BuildTree(root * 2 + 1, mid + 1, r);
    103     PushUp(root);
    104 }
    105 
    106 void PushDown(int root)
    107 {
    108     int lson = root * 2, rson = root * 2 + 1;
    109     if (tree[root].delay)
    110     {
    111         tree[lson].v = tree[rson].v = 1;
    112         tree[lson].l_color = tree[lson].r_color = tree[root].delay;
    113         tree[rson].l_color = tree[rson].r_color = tree[root].delay;
    114         tree[lson].delay = tree[rson].delay = tree[root].delay;
    115         tree[root].delay = 0;
    116     }
    117 }
    118 
    119 void Update(int root, int l, int r, int nc)
    120 {
    121     if (tree[root].r<l || tree[root].l>r) return;
    122     if (l <= tree[root].l&&tree[root].r <= r)
    123     {
    124         tree[root].delay = nc;
    125         tree[root].l_color = tree[root].r_color = nc;
    126         tree[root].v =1;
    127         return;
    128     }
    129     PushDown(root);
    130     int mid = (tree[root].r + tree[root].l) / 2;
    131     if (l <= mid)Update(root * 2, l, r, nc);
    132     if (r>mid)Update(root * 2 + 1, l, r, nc);
    133     PushUp(root);
    134 }
    135 
    136 int Query(int root, int l, int r,int&rcolor)
    137 {
    138     if (tree[root].r<l || tree[root].l>r) return 0;
    139     if (l <= tree[root].l&&tree[root].r <= r)
    140     {
    141         if (rcolor == tree[root].l_color)
    142         {
    143             rcolor = tree[root].r_color;
    144             return tree[root].v - 1;
    145         }
    146         else
    147         {
    148             rcolor = tree[root].r_color;
    149             return tree[root].v;
    150         }
    151     }
    152     PushDown(root);
    153     int mid = (tree[root].l + tree[root].r) / 2;
    154     int ans = 0;
    155     if (l <= mid) ans += Query(root * 2, l, r, rcolor);
    156     if (r > mid) ans += Query(root * 2 + 1, l, r, rcolor);
    157     PushUp(root);
    158     return ans;
    159 }
    160 
    161 int Query_color(int root, int pos ,char flag)
    162 {//查询某个分段最左或最右的颜色
    163     if (tree[root].l == pos&&flag=='l')
    164     {
    165         return tree[root].l_color;
    166     }
    167     else if (tree[root].r == pos && flag == 'r')
    168     {
    169         return tree[root].r_color;
    170     }
    171     PushDown(root);
    172     int mid = (tree[root].l + tree[root].r) / 2;
    173     int ans = 0;
    174     if (pos <= mid) ans = Query_color(root * 2, pos,flag);
    175     else ans = Query_color(root * 2 + 1, pos,flag);
    176     PushUp(root);
    177     return ans;
    178 }
    179 
    180 
    181 /*-------线段树·终————*/
    182 
    183 int Query_length(int x, int y)
    184 {//查询结点x到y路径上颜色段数
    185     int ans = 0;
    186     int fx = top[x], fy = top[y];
    187     while (fx != fy)
    188     {
    189         if (dep[fx] >= dep[fy])
    190         {
    191             int rcolor = -1;
    192             ans += Query(1, nid[fx], nid[x],rcolor);//在一条重链上的值用线段树维护、查询
    193             int tlcolor = Query_color(1, nid[fx], 'l');
    194             x = father[fx];
    195             fx = top[x];
    196             int trcolor = Query_color(1, nid[x], 'r');
    197             if (trcolor ==tlcolor) ans--;
    198         }
    199         else
    200         {
    201             int rcolor = -1;
    202             ans += Query(1, nid[fy], nid[y],rcolor);
    203             int tlcolor = Query_color(1, nid[fy], 'l');
    204             y = father[fy];
    205             fy = top[y];
    206             int trcolor = Query_color(1, nid[y], 'r');
    207             if (trcolor == tlcolor) ans--;
    208         }
    209     }
    210     //此时x与y已经在一条重链上,而重链上的编号都是连续的
    211     int rcolor = -1;
    212     if (x != y)
    213     {
    214         
    215         if (nid[x] < nid[y])
    216         {
    217             ans += Query(1, nid[x], nid[y],rcolor);
    218         }
    219         else
    220         {
    221             ans += Query(1, nid[y], nid[x],rcolor);
    222         }
    223     }
    224     else ans += Query(1, nid[x], nid[y], rcolor);
    225     return ans;
    226 }
    227 
    228 void Update_path(int x, int y, int nc)
    229 {//将x到y路径上所有结点的值都加上add
    230     int fx = top[x], fy = top[y];
    231     while (fx != fy)
    232     {
    233         if (dep[fx] >= dep[fy])
    234         {
    235             Update(1, nid[fx], nid[x], nc);
    236             x = father[fx];
    237             fx = top[x];
    238         }
    239         else
    240         {
    241             Update(1, nid[fy], nid[y], nc);
    242             y = father[fy];
    243             fy = top[y];
    244         }
    245     }
    246     if (x != y)
    247     {
    248         if (nid[x] < nid[y]) Update(1, nid[x], nid[y], nc);
    249         else Update(1, nid[y], nid[x], nc);
    250     }
    251     else Update(1, nid[x], nid[y], nc);
    252 }
    253 /*-------树链剖分·终-------*/
    254 
    255 int main()
    256 {
    257     int n, m;
    258     while (~scanf("%d%d", &n, &m))
    259     {
    260         INIT();
    261         for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
    262         for (int i = 1; i < n; i++)
    263         {
    264             int u, v;
    265             scanf("%d%d", &u, &v);
    266             addEdge(u, v);
    267         }
    268         dfs1(1,1,1);
    269         dfs2(1, 1);
    270         BuildTree(1, 1, n);
    271         char s[10];
    272         for (int i = 1; i <= m; i++)
    273         {
    274             scanf("%s", s);
    275             if (s[0] == 'Q')
    276             {
    277                 int u, v;
    278                 scanf("%d%d", &u, &v);
    279                 printf("%d
    ", Query_length(u, v));
    280             }
    281             else
    282             {
    283                 int u, v, c;
    284                 scanf("%d%d%d", &u, &v, &c);
    285                 Update_path(u, v, c);
    286             }
    287         }
    288     }
    289     return 0;
    290 }
    View Code

    3、HYSBZ - 1036 树的统计Count

      题意:一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作:

      I. CHANGE u t : 把结点u的权值改为t

      II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

      III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

      思路:树链剖分+线段树,点权,单点更新+区间查询。线段树维护区间和和最大值。

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<algorithm>
      5 using namespace std;
      6 const int maxn = 30000 + 10;
      7 const int INF = 0x3f3f3f3f;
      8 
      9 /*-------树链剖分·启-------*/
     10 
     11 int siz[maxn];//size[i]:以i为根的子树结点个数
     12 int top[maxn];//保存结点i所在链的顶端结点
     13 int son[maxn];//保存i的重儿子
     14 int dep[maxn];//保存结点i的层次(深度)
     15 int father[maxn];//保存结点i的父亲结点
     16 int nid[maxn];//保存树节点剖分后的对应新编号
     17 int oid[maxn];//保存新编号对应在剖分的树中的结点(与nid相反)
     18 int cnt = 0;//重编号
     19 int val[maxn];//结点值
     20 struct EDGE
     21 {
     22     int from, to, next;
     23     EDGE(int ff = 0, int tt = 0, int nn = 0) :from(ff), to(tt), next(nn) {}
     24 }edge[maxn * 2];
     25 int Head[maxn], totedge = 0;
     26 void addEdge(int from, int to)
     27 {
     28     edge[totedge] = EDGE(from, to, Head[from]);
     29     Head[from] = totedge++;
     30     edge[totedge] = EDGE(to, from, Head[to]);
     31     Head[to] = totedge++;
     32 }
     33 void INIT()
     34 {
     35     memset(Head, -1, sizeof(Head));
     36     totedge = 0;
     37 
     38     memset(son, -1, sizeof(son));
     39     cnt = 0;
     40 }
     41 
     42 void dfs1(int u, int fa, int layer)
     43 {
     44     dep[u] = layer;
     45     father[u] = fa;
     46     siz[u] = 1;
     47     for (int i = Head[u]; i != -1; i = edge[i].next)
     48     {
     49         int v = edge[i].to;
     50         if (v != fa)
     51         {
     52             dfs1(v, u, layer + 1);
     53             siz[u] += siz[v];
     54             if (son[u] == -1 || siz[v] > siz[son[u]])
     55             {
     56                 son[u] = v;
     57             }
     58         }
     59     }
     60 }
     61 
     62 void dfs2(int u, int Hson)
     63 {//Hson,重儿子
     64     top[u] = Hson;
     65     nid[u] = ++cnt;
     66     oid[cnt] = u;
     67     if (son[u] == -1) return;
     68     dfs2(son[u], Hson);//先将当前重链重编号
     69     for (int i = Head[u]; i != -1; i = edge[i].next)
     70     {//对不在重链上的点,自己作为子树的重链起点重编号
     71         int v = edge[i].to;
     72         if (v != son[u] && v != father[u]) dfs2(v, v);
     73     }
     74 }
     75 /*-------线段树·启————*/
     76 struct treenode
     77 {
     78     int l, r;
     79     long long sum;
     80     int max, delay;
     81     treenode(int ll = 0, int rr = 0, long long vv = 0, int mx=0,long long tt = 0) :l(ll), r(rr), sum(vv),max(mx), delay(tt) {}
     82 }tree[maxn * 4];
     83 
     84 void PushUp(int root)
     85 {
     86     tree[root].sum = tree[root * 2].sum + tree[root * 2 + 1].sum;
     87     tree[root].max = max(tree[root * 2].max, tree[root * 2 + 1].max);
     88 }
     89 
     90 void BuildTree(int root, int l, int r)
     91 {
     92     tree[root].l = l, tree[root].r = r;
     93     tree[root].delay = 0;
     94     if (l == r)
     95     {
     96         tree[root].sum = tree[root].max=val[oid[l]];
     97         return;
     98     }
     99     int mid = (l + r) / 2;
    100     BuildTree(root * 2, l, mid);
    101     BuildTree(root * 2 + 1, mid + 1, r);
    102     PushUp(root);
    103 }
    104 void Pushdown(int root)
    105 {
    106     int lson = root * 2, rson = root * 2 + 1;
    107     if (tree[root].delay)
    108     {
    109         tree[lson].sum =1ll* (tree[lson].r - tree[lson].l + 1)*tree[root].delay;
    110         tree[rson].sum = 1ll*(tree[rson].r - tree[rson].l + 1)*tree[root].delay;
    111         tree[lson].delay = tree[root].delay;
    112         tree[rson].delay = tree[root].delay;
    113         tree[lson].max = tree[rson].max = tree[root].delay;
    114         tree[root].delay = 0;
    115     }
    116 }
    117 
    118 void Update(int root, int l, int r, int v)
    119 {
    120     if (tree[root].r<l || tree[root].l>r) return;
    121     if (l <= tree[root].l&&tree[root].r <= r)
    122     {
    123         tree[root].delay = v;
    124         tree[root].max = v;
    125         tree[root].sum = 1ll*v * (tree[root].r - tree[root].l + 1);
    126         return;
    127     }
    128     Pushdown(root);
    129     int mid = (tree[root].r + tree[root].l) / 2;
    130     if (l <= mid)Update(root * 2, l, r, v);
    131     if (r>mid)Update(root * 2 + 1, l, r, v);
    132     PushUp(root);
    133 }
    134 
    135 pair<long long,int> Query(int root, int l, int r)
    136 {
    137     if (tree[root].r<l || tree[root].l>r) return make_pair(0,0);
    138     if (l <= tree[root].l&&tree[root].r <= r)
    139     {
    140         return make_pair(tree[root].sum,tree[root].max);
    141     }
    142     Pushdown(root);
    143     int mid = (tree[root].l + tree[root].r) / 2;
    144     bool flag1 = false, flag2 = false;
    145     pair<long long, int>ans,tmp1= pair<long long, int>(0,0),tmp2= pair<long long, int>(0,0);
    146     if (l <= mid) tmp1 = Query(root * 2, l, r),flag1=true;
    147     if (r > mid) tmp2 = Query(root * 2 + 1, l, r),flag2=true;
    148     PushUp(root);
    149     if (flag1&&flag2) ans.first = tmp1.first + tmp2.first, ans.second = max(tmp1.second, tmp2.second);
    150     else if (flag1) ans = tmp1;
    151     else ans = tmp2;
    152     return ans;
    153 }
    154 /*-------线段树·终————*/
    155 
    156 pair<long long, int> Query_length(int x, int y)
    157 {//查询结点x到y路径上所有结点值之和与最大值
    158     long long sum = 0;
    159     int maxv = -INF;
    160     int fx = top[x], fy = top[y];
    161     pair<long long, int>tmp;
    162     while (fx != fy)
    163     {
    164         if (dep[fx] >= dep[fy])
    165         {
    166             tmp= Query(1, nid[fx], nid[x]);//在一条重链上的值用线段树维护、查询
    167             x = father[fx];
    168             fx = top[x];
    169             sum += tmp.first, maxv = max(maxv, tmp.second);
    170         }
    171         else
    172         {
    173             tmp= Query(1, nid[fy], nid[y]);
    174             sum += tmp.first, maxv = max(maxv, tmp.second);
    175             y = father[fy];
    176             fy = top[y];
    177         }
    178     }
    179     //此时x与y已经在一条重链上,而重链上的编号都是连续的
    180     if (x != y)
    181     {
    182         if (nid[x] < nid[y])
    183         {
    184             tmp= Query(1, nid[x], nid[y]);
    185             sum += tmp.first, maxv = max(maxv, tmp.second);
    186         }
    187         else
    188         {
    189             tmp= Query(1, nid[y], nid[x]);
    190             sum += tmp.first, maxv = max(maxv, tmp.second);
    191         }
    192     }
    193     else
    194     {
    195         tmp = Query(1, nid[x], nid[y]);
    196         sum += tmp.first, maxv = max(maxv, tmp.second);
    197     }
    198     return make_pair(sum,maxv);
    199 }
    200 
    201 void Update_path(int x, int y, int add)
    202 {//将x到y路径上所有结点的值都加上add
    203     int fx = top[x], fy = top[y];
    204     while (fx != fy)
    205     {
    206         if (dep[fx] >= dep[fy])
    207         {
    208             Update(1, nid[fx], nid[x], add);
    209             x = father[fx];
    210             fx = top[x];
    211         }
    212         else
    213         {
    214             Update(1, nid[fy], nid[y], add);
    215             y = father[fy];
    216             fy = top[y];
    217         }
    218     }
    219     if (x != y)
    220     {
    221         if (nid[x] < nid[y]) Update(1, nid[x], nid[y], add);
    222         else Update(1, nid[y], nid[x], add);
    223     }
    224     else Update(1, nid[x], nid[y], add);
    225 }
    226 /*-------树链剖分·终-------*/
    227 
    228 int main()
    229 {
    230     int n,q;
    231     while (~scanf("%d", &n))
    232     {
    233         INIT();
    234         
    235         for (int i = 1; i <n; i++)
    236         {
    237             int from, to;
    238             scanf("%d%d", &from, &to);
    239             addEdge(from, to);
    240         }
    241         for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
    242         dfs1(1, 1, 1);
    243         dfs2(1, 1);
    244         BuildTree(1, 1, n);
    245         char s[10];
    246         scanf("%d", &q);
    247         for (int i = 1; i <= q; i++)
    248         {
    249             scanf("%s", s);
    250             if (s[1] == 'H')
    251             {
    252                 int u, t;
    253                 scanf("%d%d", &u, &t);
    254                 Update(1, nid[u], nid[u], t);
    255             }
    256             else
    257             {
    258                 int u, v;
    259                 scanf("%d%d", &u, &v);
    260                 pair<long long, int>ans = Query_length(u, v);
    261                 if (s[1] == 'M') printf("%d
    ", ans.second);
    262                 else printf("%lld
    ", ans.first);
    263             }
    264         }
    265     }
    266     return 0;
    267 }
    View Code

    4、FZU - 2082 过路费

      题意:有n座城市,由n-1条路相连通,使得任意两座城市之间可达。每条路有过路费,要交过路费才能通过。每条路的过路费经常会更新,现问你,当前情况下,从城市a到城市b最少要花多少过路费。

      思路:树链剖分+线段树,边权,单点更新+区间查询。注意对边进行编号,以及一些辅助数组记录边指向的结点、边权。

      1 #include<iostream>
      2 #include<cstring>
      3 #include<algorithm>
      4 using namespace std;
      5 const int maxn = 50000 + 10;
      6 
      7 /*-------树链剖分·启-------*/
      8 
      9 int siz[maxn];//size[i]:以i为根的子树结点个数
     10 int top[maxn];//保存结点i所在链的顶端结点
     11 int son[maxn];//保存i的重儿子
     12 int dep[maxn];//保存结点i的层次(深度)
     13 int father[maxn];//保存结点i的父亲结点
     14 int nid[maxn];//保存树剖分后的指向子结点的边对应的新编号
     15 int nval[maxn];//记录所指向的子结点i新编号对应边的边权,用以建立线段树
     16 int oid[maxn];//保存新编号对应在剖分的树中的所指向的子结点(与nid相反)
     17 int cnt = 0;//重编号
     18 int val[maxn];//原树中指向子结点i的边的边权值
     19 int linkto[maxn];//记录指向的子结点
     20 struct EDGE
     21 {
     22     int from, to, w, next;
     23     EDGE(int ff = 0, int tt = 0, int ww = 0, int nn = 0) :from(ff), to(tt), w(ww), next(nn) {}
     24 }edge[maxn * 2];
     25 int Head[maxn], totedge = 0;
     26 void addEdge(int from, int to, int w)
     27 {
     28     edge[totedge] = EDGE(from, to, w, Head[from]);
     29     Head[from] = totedge++;
     30     edge[totedge] = EDGE(to, from, w, Head[to]);
     31     Head[to] = totedge++;
     32 }
     33 int treeroot = 1;
     34 void INIT()
     35 {
     36     memset(Head, -1, sizeof(Head));
     37     totedge = 0;
     38 
     39     memset(son, -1, sizeof(son));
     40     memset(siz, 0, sizeof(siz));
     41     memset(father, 0, sizeof(father));
     42     memset(top, 0, sizeof(top));
     43     memset(dep, 0, sizeof(dep));
     44     cnt = 0;
     45 }
     46 
     47 void dfs1(int u, int fa, int layer)
     48 {
     49     dep[u] = layer;
     50     father[u] = fa;
     51     siz[u] = 1;
     52     for (int i = Head[u]; i != -1; i = edge[i].next)
     53     {
     54         int v = edge[i].to;
     55         if (v != fa)
     56         {
     57             dfs1(v, u, layer + 1);
     58             siz[u] += siz[v];
     59             linkto[i / 2 + 1] = v;
     60             val[v] = edge[i].w;
     61             if (son[u] == -1 || siz[v] > siz[son[u]])
     62             {
     63                 son[u] = v;
     64             }
     65         }
     66     }
     67 }
     68 
     69 void dfs2(int u, int Hson)
     70 {//Hson,重儿子
     71     top[u] = Hson;
     72     if (u != treeroot)
     73     {
     74         nid[u] = ++cnt;
     75         oid[cnt] = u;
     76         nval[cnt] = val[u];
     77     }
     78     if (son[u] == -1) return;
     79     dfs2(son[u], Hson);//先将当前重链重编号
     80     for (int i = Head[u]; i != -1; i = edge[i].next)
     81     {//对不在重链上的点,自己作为子树的重链起点重编号
     82         int v = edge[i].to;
     83         if (v != son[u] && v != father[u]) dfs2(v, v);
     84     }
     85 }
     86 /*-------线段树·启————*/
     87 struct treenode
     88 {
     89     int l, r;
     90     long long v, tmp;
     91     treenode(int ll = 0, int rr = 0, long long vv = 0, long long tt = 0) :l(ll), r(rr), v(vv), tmp(tt) {}
     92 }tree[maxn * 4];
     93 
     94 void BuildTree(int root, int l, int r)
     95 {
     96     tree[root].l = l, tree[root].r = r;
     97     tree[root].tmp = 0;
     98     if (l == r)
     99     {
    100         tree[root].v = nval[l];
    101         return;
    102     }
    103     int mid = (l + r) / 2;
    104     BuildTree(root * 2, l, mid);
    105     BuildTree(root * 2 + 1, mid + 1, r);
    106     tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v;
    107 }
    108 void Pushdown(int root)
    109 {
    110     int lson = root * 2, rson = root * 2 + 1;
    111     if (tree[root].tmp)
    112     {
    113         tree[lson].v = (tree[lson].r - tree[lson].l + 1)*tree[root].tmp;
    114         tree[rson].v = (tree[rson].r - tree[rson].l + 1)*tree[root].tmp;
    115         tree[lson].tmp = tree[root].tmp;
    116         tree[rson].tmp = tree[root].tmp;
    117         tree[root].tmp = 0;
    118     }
    119 }
    120 void PushUp(int root)
    121 {
    122     tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v;
    123 }
    124 void Update(int root, int l, int r, int add)
    125 {
    126     if (tree[root].r<l || tree[root].l>r) return;
    127     if (l <= tree[root].l&&tree[root].r <= r)
    128     {
    129         tree[root].tmp = add;
    130         tree[root].v = add * (tree[root].r - tree[root].l + 1);
    131         return;
    132     }
    133     Pushdown(root);
    134     int mid = (tree[root].r + tree[root].l) / 2;
    135     if (l <= mid)Update(root * 2, l, r, add);
    136     if (r>mid)Update(root * 2 + 1, l, r, add);
    137     PushUp(root);
    138 }
    139 
    140 long long Query(int root, int l, int r)
    141 {
    142     if (tree[root].r<l || tree[root].l>r) return 0;
    143     if (l <= tree[root].l&&tree[root].r <= r)
    144     {
    145         return tree[root].v;
    146     }
    147     Pushdown(root);
    148     long long tsum = Query(root * 2, l, r) + Query(root * 2 + 1, l, r);
    149     PushUp(root);
    150     return tsum;
    151 }
    152 /*-------线段树·终————*/
    153 
    154 long long Query_length(int x, int y)
    155 {//查询x到y路径上边权和
    156     int fx = top[x], fy = top[y];
    157     long long ans = 0;
    158     while (fx != fy)
    159     {
    160         if (dep[fx] > dep[fy])
    161         {
    162             int id1 = nid[fx], id2 = nid[x];
    163             ans += Query(1, id1, id2);
    164             x = father[fx];
    165             fx = top[x];
    166         }
    167         else
    168         {
    169             int id1 = nid[fy], id2 = nid[y];
    170             ans += Query(1, id1, id2);
    171             y = father[fy];
    172             fy = top[y];
    173         }
    174     }
    175     if (x != y)
    176     {
    177         if (dep[x] > dep[y])
    178         {
    179             int id1 = nid[son[y]], id2 = nid[x];
    180             ans += Query(1, id1, id2);
    181         }
    182         else
    183         {
    184             int id1 = nid[son[x]], id2 = nid[y];
    185             ans += Query(1, id1, id2);
    186         }
    187     }
    188     return ans;
    189 }
    190 void Update_path(int x, int y, int add)
    191 {//将x到y路径上所有边的值都加上或修改为add
    192     int fx = top[x], fy = top[y];
    193     while (fx != fy)
    194     {
    195         if (dep[fx] >= dep[fy])
    196         {
    197             Update(1, nid[fx], nid[x], add);
    198             x = father[fx];
    199             fx = top[x];
    200         }
    201         else
    202         {
    203             Update(1, nid[fy], nid[y], add);
    204             y = father[fy];
    205             fy = top[y];
    206         }
    207     }
    208     if (x != y)
    209     {
    210         if (dep[x] < dep[y]) Update(1, nid[son[x]], nid[y], add);
    211         else Update(1, nid[son[y]], nid[x], add);
    212     }
    213 }
    214 /*-------树链剖分·终-------*/
    215 
    216 int main()
    217 {
    218     int n, m;
    219     while (~scanf("%d%d", &n, &m))
    220     {
    221         INIT();
    222         for (int i = 1; i < n; i++)
    223         {
    224             int u, v, w;
    225             scanf("%d%d%d", &u, &v, &w);
    226             addEdge(u, v, w);
    227         }
    228         dfs1(1, 1, 1);
    229         dfs2(1, 1);
    230         BuildTree(1, 1, cnt);
    231         for (int i = 1; i <= m; i++)
    232         {
    233             int flag;
    234             scanf("%d", &flag);
    235             if (flag == 1)
    236             {
    237                 int u,v;
    238                 scanf("%d%d", &u,&v);
    239                 long long ans = Query_length(u,v);
    240                 printf("%lld
    ", ans);
    241             }
    242             else
    243             {
    244                 int id, v;
    245                 scanf("%d%d", &id, &v);
    246                 int nID = nid[linkto[id]];
    247                 Update(1, nID, nID, v);
    248             }
    249 
    250         }
    251 
    252     }
    253     return 0;
    254 }
    View Code

     5、LightOJ - 1348 Aladdin and the Return Journey

      题意:有一棵树,每次更新一个点的权值或者查询u到v路径上所有结点权值之和。

      思路:树链剖分+线段树,点权,单点更新和区间查询。

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 using namespace std;
      5 const int maxn = 30000 + 10;
      6 
      7 /*-------树链剖分·启-------*/
      8 
      9 int siz[maxn];//size[i]:以i为根的子树结点个数
     10 int top[maxn];//保存结点i所在链的顶端结点
     11 int son[maxn];//保存i的重儿子
     12 int dep[maxn];//保存结点i的层次(深度)
     13 int father[maxn];//保存结点i的父亲结点
     14 int nid[maxn];//保存树节点剖分后的对应新编号
     15 int oid[maxn];//保存新编号对应在剖分的树中的结点(与nid相反)
     16 int cnt = 0;//重编号
     17 int val[maxn];//结点值
     18 struct EDGE
     19 {
     20     int from, to, next;
     21     EDGE(int ff = 0, int tt = 0, int nn = 0) :from(ff), to(tt), next(nn) {}
     22 }edge[maxn * 2];
     23 int Head[maxn], totedge = 0;
     24 void addEdge(int from, int to)
     25 {
     26     edge[totedge] = EDGE(from, to, Head[from]);
     27     Head[from] = totedge++;
     28     edge[totedge] = EDGE(to, from, Head[to]);
     29     Head[to] = totedge++;
     30 }
     31 void INIT()
     32 {
     33     memset(Head, -1, sizeof(Head));
     34     totedge = 0;
     35 
     36     memset(son, -1, sizeof(son));
     37     memset(siz, 0, sizeof(siz));
     38     memset(father, 0, sizeof(father));
     39     memset(top, 0, sizeof(top));
     40     memset(dep, 0, sizeof(dep));
     41     cnt = 0;
     42 }
     43 
     44 void dfs1(int u, int fa, int layer)
     45 {
     46     dep[u] = layer;
     47     father[u] = fa;
     48     siz[u] = 1;
     49     for (int i = Head[u]; i != -1; i = edge[i].next)
     50     {
     51         int v = edge[i].to;
     52         if (v != fa)
     53         {
     54             dfs1(v, u, layer + 1);
     55             siz[u] += siz[v];
     56             if (son[u] == -1 || siz[v] > siz[son[u]])
     57             {
     58                 son[u] = v;
     59             }
     60         }
     61     }
     62 }
     63 
     64 void dfs2(int u, int Hson)
     65 {//Hson,重儿子
     66     top[u] = Hson;
     67     nid[u] = ++cnt;
     68     oid[cnt] = u;
     69     if (son[u] == -1) return;
     70     dfs2(son[u], Hson);//先将当前重链重编号
     71     for (int i = Head[u]; i != -1; i = edge[i].next)
     72     {//对不在重链上的点,自己作为子树的重链起点重编号
     73         int v = edge[i].to;
     74         if (v != son[u] && v != father[u]) dfs2(v, v);
     75     }
     76 }
     77 /*-------线段树·启————*/
     78 struct treenode
     79 {
     80     int l, r;
     81     long long v, delay;
     82     treenode(int ll = 0, int rr = 0, long long vv = 0, long long tt = 0) :l(ll), r(rr), v(vv), delay(tt) {}
     83 }tree[maxn * 4];
     84 
     85 void PushUp(int root)
     86 {
     87     tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v;
     88 }
     89 void BuildTree(int root, int l, int r)
     90 {
     91     tree[root].l = l, tree[root].r = r;
     92     tree[root].delay = 0;
     93     if (l == r)
     94     {
     95         tree[root].v = val[oid[l]];
     96         return;
     97     }
     98     int mid = (l + r) / 2;
     99     BuildTree(root * 2, l, mid);
    100     BuildTree(root * 2 + 1, mid + 1, r);
    101     tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v;
    102 }
    103 void Pushdown(int root)
    104 {
    105     int lson = root * 2, rson = root * 2 + 1;
    106     if (tree[root].delay)
    107     {
    108         tree[lson].v = (tree[lson].r - tree[lson].l + 1)*tree[root].delay;
    109         tree[rson].v = (tree[rson].r - tree[rson].l + 1)*tree[root].delay;
    110         tree[lson].delay = tree[root].delay;
    111         tree[rson].delay = tree[root].delay;
    112         tree[root].delay = 0;
    113     }
    114 }
    115 
    116 void Update(int root, int l, int r, int add)
    117 {
    118     if (tree[root].r<l || tree[root].l>r) return;
    119     if (l <= tree[root].l&&tree[root].r <= r)
    120     {
    121         tree[root].delay = add;
    122         tree[root].v = add * (tree[root].r - tree[root].l + 1);
    123         return;
    124     }
    125     Pushdown(root);
    126     int mid = (tree[root].r + tree[root].l) / 2;
    127     if (l <= mid)Update(root * 2, l, r, add);
    128     if (r>mid)Update(root * 2 + 1, l, r, add);
    129     PushUp(root);
    130 }
    131 
    132 long long Query(int root, int l, int r)
    133 {
    134     if (tree[root].r<l || tree[root].l>r) return 0;
    135     if (l <= tree[root].l&&tree[root].r <= r)
    136     {
    137         return tree[root].v;
    138     }
    139     Pushdown(root);
    140     long long tsum = Query(root * 2, l, r) + Query(root * 2 + 1, l, r);
    141     PushUp(root);
    142     return tsum;
    143 }
    144 /*-------线段树·终————*/
    145 
    146 long long Query_length(int x, int y)
    147 {//查询结点x到y路径上所有结点值之和
    148     long long ans = 0;
    149     int fx = top[x], fy = top[y];
    150     while (fx != fy)
    151     {
    152         if (dep[fx] >= dep[fy])
    153         {
    154             ans += Query(1, nid[fx], nid[x]);//在一条重链上的值用线段树维护、查询
    155             x = father[fx];
    156             fx = top[x];
    157         }
    158         else
    159         {
    160             ans += Query(1, nid[fy], nid[y]);
    161             y = father[fy];
    162             fy = top[y];
    163         }
    164     }
    165     //此时x与y已经在一条重链上,而重链上的编号都是连续的
    166     if (x != y)
    167     {
    168         if (nid[x] < nid[y])
    169         {
    170             ans += Query(1, nid[x], nid[y]);
    171         }
    172         else
    173         {
    174             ans += Query(1, nid[y], nid[x]);
    175         }
    176     }
    177     else ans += Query(1, nid[x], nid[y]);
    178     return ans;
    179 }
    180 
    181 void Update_path(int x, int y, int add)
    182 {//将x到y路径上所有结点的值都加上add
    183     int fx = top[x], fy = top[y];
    184     while (fx != fy)
    185     {
    186         if (dep[fx] >= dep[fy])
    187         {
    188             Update(1, nid[fx], nid[x], add);
    189             x = father[fx];
    190             fx = top[x];
    191         }
    192         else
    193         {
    194             Update(1, nid[fy], nid[y], add);
    195             y = father[fy];
    196             fy = top[y];
    197         }
    198     }
    199     if (x != y)
    200     {
    201         if (nid[x] < nid[y]) Update(1, nid[x], nid[y], add);
    202         else Update(1, nid[y], nid[x], add);
    203     }
    204     else Update(1, nid[x], nid[y], add);
    205 }
    206 /*-------树链剖分·终-------*/
    207 
    208 int main()
    209 {
    210     int t,n,q;
    211     int Case = 1;
    212     scanf("%d", &t);
    213     while (t--)
    214     {
    215         printf("Case %d:
    ", Case++);
    216         scanf("%d", &n);
    217         INIT();
    218         for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
    219         for (int i = 1; i <n; i++)
    220         {
    221             int from, to;
    222             scanf("%d%d", &from, &to);
    223             from++, to++;//改为从1开始编号
    224             addEdge(from, to);
    225         }
    226         dfs1(1, 1, 1);
    227         dfs2(1, 1);
    228         BuildTree(1, 1, n);
    229         scanf("%d", &q);
    230         for (int i = 1; i <= q; i++)
    231         {
    232             int op;
    233             scanf("%d", &op);
    234             if (op == 0)
    235             {
    236                 int u, v;
    237                 scanf("%d%d", &u, &v);
    238                 u++, v++;
    239                 printf("%lld
    ", Query_length(u, v));
    240             }
    241             else
    242             {
    243                 int u, t;
    244                 scanf("%d%d", &u, &t);
    245                 u++;
    246                 Update(1, nid[u], nid[u], t);
    247             }
    248         }
    249     }
    250     return 0;
    251 }
    View Code

     6、Housewife Wind POJ - 2763

      题意:有一个小镇,有n户人家和n-1条路(树),有一位母亲要去接孩子,起点位于s。两种操作:修改通过某一条路的时间;母亲要从当前位置到达u的位置接孩子,求时间。

      思路:树链剖分+线段树,边权,区间查询+单点更新。

      1 #include<iostream>
      2 #include<cstring>
      3 using namespace std;
      4 const int maxn = 100000+10;
      5 
      6 /*-------树链剖分·启-------*/
      7 
      8 int siz[maxn];//size[i]:以i为根的子树结点个数
      9 int top[maxn];//保存结点i所在链的顶端结点
     10 int son[maxn];//保存i的重儿子
     11 int dep[maxn];//保存结点i的层次(深度)
     12 int father[maxn];//保存结点i的父亲结点
     13 int nid[maxn];//保存树剖分后的指向子结点的边对应的新编号
     14 int nval[maxn];//记录所指向的子结点i新编号对应边的边权,用以建立线段树
     15 int oid[maxn];//保存新编号对应在剖分的树中的所指向的子结点(与nid相反)
     16 int cnt = 0;//重编号
     17 int val[maxn];//原树中指向子结点i的边的边权值
     18 int linkto[maxn];//记录指向的子结点
     19 struct EDGE
     20 {
     21     int from, to,w, next;
     22     EDGE(int ff = 0, int tt = 0,int ww=0, int nn = 0) :from(ff), to(tt),w(ww), next(nn) {}
     23 }edge[maxn * 2];
     24 int Head[maxn], totedge = 0;
     25 void addEdge(int from, int to,int w)
     26 {
     27     edge[totedge] = EDGE(from, to, w,Head[from]);
     28     Head[from] = totedge++;
     29     edge[totedge] = EDGE(to, from,w, Head[to]);
     30     Head[to] = totedge++;
     31 }
     32 int treeroot = 1;
     33 void INIT()
     34 {
     35     memset(Head, -1, sizeof(Head));
     36     totedge = 0;
     37 
     38     memset(son, -1, sizeof(son));
     39     memset(siz, 0, sizeof(siz));
     40     memset(father, 0, sizeof(father));
     41     memset(top, 0, sizeof(top));
     42     memset(dep, 0, sizeof(dep));
     43     cnt = 0;
     44 }
     45 
     46 void dfs1(int u, int fa, int layer)
     47 {
     48     dep[u] = layer;
     49     father[u] = fa;
     50     siz[u] = 1;
     51     for (int i = Head[u]; i != -1; i = edge[i].next)
     52     {
     53         int v = edge[i].to;
     54         if (v != fa)
     55         {
     56             dfs1(v, u, layer + 1);
     57             siz[u] += siz[v];
     58             linkto[i / 2 + 1] = v;
     59             val[v] = edge[i].w;
     60             if (son[u] == -1 || siz[v] > siz[son[u]])
     61             {
     62                 son[u] = v;
     63             }
     64         }
     65     }
     66 }
     67 
     68 void dfs2(int u, int Hson)
     69 {//Hson,重儿子
     70     top[u] = Hson;
     71     if (u != treeroot)
     72     {
     73         nid[u] = ++cnt;
     74         oid[cnt] = u;
     75         nval[cnt] = val[u];
     76     }
     77     if (son[u] == -1) return;
     78     dfs2(son[u], Hson);//先将当前重链重编号
     79     for (int i = Head[u]; i != -1; i = edge[i].next)
     80     {//对不在重链上的点,自己作为子树的重链起点重编号
     81         int v = edge[i].to;
     82         if (v != son[u] && v != father[u]) dfs2(v, v);
     83     }
     84 }
     85 /*-------线段树·启————*/
     86 struct treenode
     87 {
     88     int l, r;
     89     long long v, tmp;
     90     treenode(int ll = 0, int rr = 0, long long vv = 0, long long tt = 0) :l(ll), r(rr), v(vv), tmp(tt) {}
     91 }tree[maxn * 4];
     92 
     93 void BuildTree(int root, int l, int r)
     94 {
     95     tree[root].l = l, tree[root].r = r;
     96     tree[root].tmp = 0;
     97     if (l == r)
     98     {
     99         tree[root].v = nval[l];
    100         return;
    101     }
    102     int mid = (l + r) / 2;
    103     BuildTree(root * 2, l, mid);
    104     BuildTree(root * 2 + 1, mid + 1, r);
    105     tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v;
    106 }
    107 void Pushdown(int root)
    108 {
    109     int lson = root * 2, rson = root * 2 + 1;
    110     if (tree[root].tmp)
    111     {
    112         tree[lson].v = (tree[lson].r - tree[lson].l + 1)*tree[root].tmp;
    113         tree[rson].v = (tree[rson].r - tree[rson].l + 1)*tree[root].tmp;
    114         tree[lson].tmp = tree[root].tmp;
    115         tree[rson].tmp = tree[root].tmp;
    116         tree[root].tmp = 0;
    117     }
    118 }
    119 void PushUp(int root)
    120 {
    121     tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v;
    122 }
    123 void Update(int root, int l, int r, int add)
    124 {
    125     if (tree[root].r<l || tree[root].l>r) return;
    126     if (l <= tree[root].l&&tree[root].r <= r)
    127     {
    128         tree[root].tmp = add;
    129         tree[root].v = add*(tree[root].r-tree[root].l+1);
    130         return;
    131     }
    132     Pushdown(root);
    133     int mid = (tree[root].r + tree[root].l) / 2;
    134     if (l <= mid)Update(root * 2, l, r, add);
    135     if (r>mid)Update(root * 2 + 1, l, r, add);
    136     PushUp(root);
    137 }
    138 
    139 long long Query(int root, int l, int r)
    140 {
    141     if (tree[root].r<l || tree[root].l>r) return 0;
    142     if (l <= tree[root].l&&tree[root].r <= r)
    143     {
    144         return tree[root].v;
    145     }
    146     Pushdown(root);
    147     long long tsum = Query(root * 2, l, r) + Query(root * 2 + 1, l, r);
    148     PushUp(root);
    149     return tsum;
    150 }
    151 /*-------线段树·终————*/
    152 
    153 long long Query_length(int x, int y)
    154 {//查询x到y路径上边权和
    155     int fx = top[x], fy = top[y];
    156     long long ans = 0;
    157     while (fx != fy)
    158     {
    159         if (dep[fx] > dep[fy])
    160         {
    161             int id1 = nid[fx],id2=nid[x];
    162             ans += Query(1, id1, id2);
    163             x = father[fx];
    164             fx = top[x];
    165         }
    166         else
    167         {
    168             int id1 = nid[fy], id2 = nid[y];
    169             ans += Query(1, id1, id2);
    170             y = father[fy];
    171             fy = top[y];
    172         }
    173     }
    174     if (x != y)
    175     {
    176         if (dep[x] > dep[y])
    177         {
    178             int id1 = nid[son[y]], id2 = nid[x];
    179             ans += Query(1, id1, id2);
    180         }
    181         else
    182         {
    183             int id1 = nid[son[x]], id2 = nid[y];
    184             ans += Query(1, id1, id2);
    185         }
    186     }
    187     return ans;
    188 }
    189 void Update_path(int x, int y, int add)
    190 {//将x到y路径上所有边的值都加上或修改为add
    191     int fx = top[x], fy = top[y];
    192     while (fx != fy)
    193     {
    194         if (dep[fx] >= dep[fy])
    195         {
    196             Update(1, nid[fx], nid[x], add);
    197             x = father[fx];
    198             fx = top[x];
    199         }
    200         else
    201         {
    202             Update(1, nid[fy], nid[y], add);
    203             y = father[fy];
    204             fy = top[y];
    205         }
    206     }
    207     if (x != y)
    208     {
    209         if (dep[x] < dep[y]) Update(1, nid[son[x]], nid[y], add);
    210         else Update(1, nid[son[y]], nid[x], add);
    211     }
    212 }
    213 /*-------树链剖分·终-------*/
    214 
    215 int main()
    216 {
    217     int n, q, s;
    218     while (~scanf("%d%d%d", &n, &q, &s))
    219     {
    220         INIT();
    221         for (int i = 1; i < n; i++)
    222         {
    223             int u, v, w;
    224             scanf("%d%d%d", &u, &v, &w);
    225             addEdge(u, v, w);
    226         }
    227         dfs1(1,1,1);
    228         dfs2(1,1);
    229         BuildTree(1, 1, cnt);
    230         for (int i = 1; i <= q; i++)
    231         {
    232             int flag;
    233             scanf("%d", &flag);
    234             if (flag == 0)
    235             {
    236                 int des;
    237                 scanf("%d", &des);
    238                 long long ans = Query_length(s, des);
    239                 s = des;
    240                 printf("%lld
    ", ans);
    241             }
    242             else
    243             {
    244                 int id, v;
    245                 scanf("%d%d", &id, &v);
    246                 int nID = nid[linkto[id]];
    247                 Update(1, nID, nID, v);
    248             }
    249 
    250         }
    251 
    252     }
    253     return 0;
    254 }
    View Code

    7、Query on a tree SPOJ - QTREE

       题意:有一棵树,每次将一条边的权值修改或者询问u到v路径上的最大边权。

      思路:树链剖分+线段树,边权,区间查询+单点更新。

      1 #include<iostream>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<cstdio>
      5 using namespace std;
      6 const int maxn = 10000 + 10;
      7 
      8 /*-------树链剖分·启-------*/
      9 
     10 int siz[maxn];//size[i]:以i为根的子树结点个数
     11 int top[maxn];//保存结点i所在链的顶端结点
     12 int son[maxn];//保存i的重儿子
     13 int dep[maxn];//保存结点i的层次(深度)
     14 int father[maxn];//保存结点i的父亲结点
     15 int nid[maxn];//保存树剖分后的指向子结点的边对应的新编号
     16 int nval[maxn];//记录所指向的子结点i新编号对应边的边权,用以建立线段树
     17 int oid[maxn];//保存新编号对应在剖分的树中的所指向的子结点(与nid相反)
     18 int cnt = 0;//重编号
     19 int val[maxn];//原树中指向子结点i的边的边权值
     20 int linkto[maxn];//记录指向的子结点
     21 struct EDGE
     22 {
     23     int from, to, w, next;
     24     EDGE(int ff = 0, int tt = 0, int ww = 0, int nn = 0) :from(ff), to(tt), w(ww), next(nn) {}
     25 }edge[maxn * 2];
     26 int Head[maxn], totedge = 0;
     27 void addEdge(int from, int to, int w)
     28 {
     29     edge[totedge] = EDGE(from, to, w, Head[from]);
     30     Head[from] = totedge++;
     31     edge[totedge] = EDGE(to, from, w, Head[to]);
     32     Head[to] = totedge++;
     33 }
     34 int treeroot = 1;
     35 void INIT()
     36 {
     37     memset(Head, -1, sizeof(Head));
     38     totedge = 0;
     39 
     40     memset(son, -1, sizeof(son));
     41     memset(siz, 0, sizeof(siz));
     42     memset(father, 0, sizeof(father));
     43     memset(top, 0, sizeof(top));
     44     memset(dep, 0, sizeof(dep));
     45     cnt = 0;
     46 }
     47 
     48 void dfs1(int u, int fa, int layer)
     49 {
     50     dep[u] = layer;
     51     father[u] = fa;
     52     siz[u] = 1;
     53     for (int i = Head[u]; i != -1; i = edge[i].next)
     54     {
     55         int v = edge[i].to;
     56         if (v != fa)
     57         {
     58             dfs1(v, u, layer + 1);
     59             siz[u] += siz[v];
     60             linkto[i / 2 + 1] = v;
     61             val[v] = edge[i].w;
     62             if (son[u] == -1 || siz[v] > siz[son[u]])
     63             {
     64                 son[u] = v;
     65             }
     66         }
     67     }
     68 }
     69 
     70 void dfs2(int u, int Hson)
     71 {//Hson,重儿子
     72     top[u] = Hson;
     73     if (u != treeroot)
     74     {
     75         nid[u] = ++cnt;
     76         oid[cnt] = u;
     77         nval[cnt] = val[u];
     78     }
     79     if (son[u] == -1) return;
     80     dfs2(son[u], Hson);//先将当前重链重编号
     81     for (int i = Head[u]; i != -1; i = edge[i].next)
     82     {//对不在重链上的点,自己作为子树的重链起点重编号
     83         int v = edge[i].to;
     84         if (v != son[u] && v != father[u]) dfs2(v, v);
     85     }
     86 }
     87 /*-------线段树·启————*/
     88 struct treenode
     89 {
     90     int l, r;
     91     long long v, tmp;
     92     treenode(int ll = 0, int rr = 0, long long vv = 0, long long tt = 0) :l(ll), r(rr), v(vv), tmp(tt) {}
     93 }tree[maxn * 4];
     94 
     95 void PushUp(int root)
     96 {
     97     tree[root].v = max(tree[root * 2].v, tree[root * 2 + 1].v);
     98 }
     99 
    100 void BuildTree(int root, int l, int r)
    101 {
    102     tree[root].l = l, tree[root].r = r;
    103     tree[root].tmp = 0;
    104     if (l == r)
    105     {
    106         tree[root].v = nval[l];
    107         return;
    108     }
    109     int mid = (l + r) / 2;
    110     BuildTree(root * 2, l, mid);
    111     BuildTree(root * 2 + 1, mid + 1, r);
    112     tree[root].v = max(tree[root * 2].v, tree[root * 2 + 1].v);
    113 }
    114 void PushDown(int root)
    115 {
    116     int lson = root * 2, rson = root * 2 + 1;
    117     if (tree[root].tmp)
    118     {
    119         tree[lson].v = (tree[lson].r - tree[lson].l + 1)*tree[root].tmp;
    120         tree[rson].v = (tree[rson].r - tree[rson].l + 1)*tree[root].tmp;
    121         tree[lson].tmp = tree[root].tmp;
    122         tree[rson].tmp = tree[root].tmp;
    123         tree[root].tmp = 0;
    124     }
    125 }
    126 
    127 void Update(int root, int l, int r, int add)
    128 {
    129     if (tree[root].r<l || tree[root].l>r) return;
    130     if (l <= tree[root].l&&tree[root].r <= r)
    131     {
    132         tree[root].tmp = add;
    133         tree[root].v = add * (tree[root].r - tree[root].l + 1);
    134         return;
    135     }
    136     PushDown(root);
    137     int mid = (tree[root].r + tree[root].l) / 2;
    138     if (l <= mid)Update(root * 2, l, r, add);
    139     if (r>mid)Update(root * 2 + 1, l, r, add);
    140     PushUp(root);
    141 }
    142 
    143 long long Query(int root, int l, int r)
    144 {
    145     if (tree[root].r<l || tree[root].l>r) return 0;
    146     if (l <= tree[root].l&&tree[root].r <= r)
    147     {
    148         return tree[root].v;
    149     }
    150     PushDown(root);
    151     long long ans = 0, tmp1, tmp2;
    152     bool flag = false;
    153     int mid = (tree[root].l + tree[root].r) / 2;
    154     if (l <= mid) tmp1 = Query(root * 2, l, r), flag = true;
    155     if (r > mid) tmp2 = Query(root * 2 + 1, l, r);
    156     PushUp(root);
    157     if (flag) ans = max(tmp1, tmp2);
    158     else ans = tmp2;
    159     return ans;
    160 }
    161 /*-------线段树·终————*/
    162 
    163 long long Query_length(int x, int y)
    164 {//查询x到y路径上最大边权
    165     int fx = top[x], fy = top[y];
    166     long long ans = 0;
    167     bool flag = false;
    168     while (fx != fy)
    169     {
    170         if (dep[fx] > dep[fy])
    171         {
    172 
    173             int id1 = nid[fx], id2 = nid[x];
    174             long long tmp = Query(1, id1, id2);
    175             x = father[fx];
    176             fx = top[x];
    177             if (!flag) ans = tmp;
    178             else ans = max(ans, tmp);
    179             flag = true;
    180         }
    181         else
    182         {
    183             int id1 = nid[fy], id2 = nid[y];
    184             long long tmp = Query(1, id1, id2);
    185             y = father[fy];
    186             fy = top[y];
    187             if (!flag) ans = tmp;
    188             else ans = max(ans, tmp);
    189             flag = true;
    190         }
    191     }
    192     if (x != y)
    193     {
    194         if (dep[x] > dep[y])
    195         {
    196 
    197             int id1 = nid[son[y]], id2 = nid[x];
    198             long long tmp = Query(1, id1, id2);
    199             if (!flag) ans = tmp;
    200             else ans = max(ans, tmp);
    201             flag = true;
    202         }
    203         else
    204         {
    205             int id1 = nid[son[x]], id2 = nid[y];
    206             long long tmp = Query(1, id1, id2);
    207             if (!flag) ans = tmp;
    208             else ans = max(ans, tmp);
    209             flag = true;
    210         }
    211     }
    212     return ans;
    213 }
    214 void Update_path(int x, int y, int add)
    215 {//将x到y路径上所有边的值都加上或修改为add
    216     int fx = top[x], fy = top[y];
    217     while (fx != fy)
    218     {
    219         if (dep[fx] >= dep[fy])
    220         {
    221             Update(1, nid[fx], nid[x], add);
    222             x = father[fx];
    223             fx = top[x];
    224         }
    225         else
    226         {
    227             Update(1, nid[fy], nid[y], add);
    228             y = father[fy];
    229             fy = top[y];
    230         }
    231     }
    232     if (x != y)
    233     {
    234         if (dep[x] < dep[y]) Update(1, nid[son[x]], nid[y], add);
    235         else Update(1, nid[son[y]], nid[x], add);
    236     }
    237 }
    238 /*-------树链剖分·终-------*/
    239 
    240 int main()
    241 {
    242     int t;
    243     scanf("%d", &t);
    244     int n, m;
    245     while (t--)
    246     {
    247         INIT();
    248         scanf("%d", &n);
    249         for (int i = 1; i < n; i++)
    250         {
    251             int u, v, w;
    252             scanf("%d%d%d", &u, &v, &w);
    253             addEdge(u, v, w);
    254         }
    255         dfs1(1, 1, 1);
    256         dfs2(1, 1);
    257         BuildTree(1, 1, cnt);
    258         char s[10];
    259         while (true)
    260         {
    261             scanf("%s", s);
    262             if (s[0] == 'Q')
    263             {
    264                 int u, v;
    265                 scanf("%d%d", &u, &v);
    266                 long long ans = Query_length(u, v);
    267                 printf("%lld
    ", ans);
    268             }
    269             else if (s[0] == 'C')
    270             {
    271                 int id, v;
    272                 scanf("%d%d", &id, &v);
    273                 int nID = nid[linkto[id]];
    274                 Update(1, nID, nID, v);
    275             }
    276             else
    277             {
    278                 break;
    279             }
    280         }
    281     }
    282     return 0;
    283 }
    View Code

     8、POJ - 3237 Tree 

      题意:有一棵树,每次改变一条边的边权,或将一条路径上所有边权取反,或者求一条路径上边权的最大值。

      思路:树链剖分+线段树,边权。主要练习取反。记录一个错误:建树时忘记向上更新最小值,只更新了最大值,调了好久没发现。

      1 #include<iostream>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<cstdio>
      5 using namespace std;
      6 const int maxn = 10000+ 10;
      7 
      8 /*-------树链剖分·启-------*/
      9 
     10 int siz[maxn];//size[i]:以i为根的子树结点个数
     11 int top[maxn];//保存结点i所在链的顶端结点
     12 int son[maxn];//保存i的重儿子
     13 int dep[maxn];//保存结点i的层次(深度)
     14 int father[maxn];//保存结点i的父亲结点
     15 int nid[maxn];//保存树剖分后的指向子结点的边对应的新编号
     16 int nval[maxn];//记录所指向的子结点i新编号对应边的边权,用以建立线段树
     17 int oid[maxn];//保存新编号对应在剖分的树中的所指向的子结点(与nid相反)
     18 int cnt = 0;//重编号
     19 int val[maxn];//原树中指向子结点i的边的边权值
     20 int linkto[maxn];//记录指向的子结点
     21 struct EDGE
     22 {
     23     int from, to, w, next;
     24     EDGE(int ff = 0, int tt = 0, int ww = 0, int nn = 0) :from(ff), to(tt), w(ww), next(nn) {}
     25 }edge[maxn * 2];
     26 int Head[maxn], totedge = 0;
     27 void addEdge(int from, int to, int w)
     28 {
     29     edge[totedge] = EDGE(from, to, w, Head[from]);
     30     Head[from] = totedge++;
     31     edge[totedge] = EDGE(to, from, w, Head[to]);
     32     Head[to] = totedge++;
     33 }
     34 int treeroot = 1;
     35 void INIT()
     36 {
     37     memset(Head, -1, sizeof(Head));
     38     totedge = 0;
     39 
     40     memset(son, -1, sizeof(son));
     41     cnt = 0;
     42 }
     43 
     44 void dfs1(int u, int fa, int layer)
     45 {
     46     dep[u] = layer;
     47     father[u] = fa;
     48     siz[u] = 1;
     49     for (int i = Head[u]; i != -1; i = edge[i].next)
     50     {
     51         int v = edge[i].to;
     52         if (v != fa)
     53         {
     54             dfs1(v, u, layer + 1);
     55             siz[u] += siz[v];
     56             linkto[i / 2 + 1] = v;
     57             val[v] = edge[i].w;
     58             if (son[u] == -1 || siz[v] > siz[son[u]])
     59             {
     60                 son[u] = v;
     61             }
     62         }
     63     }
     64 }
     65 
     66 void dfs2(int u, int Hson)
     67 {//Hson,重儿子
     68     top[u] = Hson;
     69     if (u != treeroot)
     70     {
     71         nid[u] = ++cnt;
     72         oid[cnt] = u;
     73         nval[cnt] = val[u];
     74     }
     75     if (son[u] == -1) return;
     76     dfs2(son[u], Hson);//先将当前重链重编号
     77     for (int i = Head[u]; i != -1; i = edge[i].next)
     78     {//对不在重链上的点,自己作为子树的重链起点重编号
     79         int v = edge[i].to;
     80         if (v != son[u] && v != father[u]) dfs2(v, v);
     81     }
     82 }
     83 /*-------线段树·启————*/
     84 struct treenode
     85 {
     86     int l, r;
     87     long long maxv, minv;
     88     int delay;
     89     treenode(int ll = 0, int rr = 0, long long vv = 0, long long mv = 0, int tt = 0) :l(ll), r(rr), maxv(vv), minv(mv), delay(tt) {}
     90 }tree[maxn * 4];
     91 
     92 void PushUp(int root)
     93 {
     94     tree[root].maxv = max(tree[root * 2].maxv, tree[root * 2 + 1].maxv);
     95     tree[root].minv = min(tree[root * 2].minv, tree[root * 2 + 1].minv);
     96 }
     97 
     98 void BuildTree(int root, int l, int r)
     99 {
    100     tree[root].l = l, tree[root].r = r;
    101     tree[root].delay = 0;
    102     if (l == r)
    103     {
    104         tree[root].maxv = tree[root].minv = nval[l];
    105         return;
    106     }
    107     int mid = (l + r) / 2;
    108     BuildTree(root * 2, l, mid);
    109     BuildTree(root * 2 + 1, mid + 1, r);
    110     PushUp(root);
    111 }
    112 void PushDown(int root)
    113 {
    114     int lson = root * 2, rson = root * 2 + 1;
    115     if (tree[root].delay)
    116     {
    117         swap(tree[lson].maxv, tree[lson].minv);
    118         tree[lson].maxv = -tree[lson].maxv, tree[lson].minv = -tree[lson].minv;
    119         swap(tree[rson].maxv, tree[rson].minv);
    120         tree[rson].maxv = -tree[rson].maxv, tree[rson].minv = -tree[rson].minv;
    121         tree[lson].delay ^= 1;
    122         tree[rson].delay ^= 1;
    123         tree[root].delay = 0;
    124     }
    125 }
    126 
    127 void Update(int root, int l, int r, int v)
    128 {//单点修改
    129     if (tree[root].r<l || tree[root].l>r) return;
    130     if (tree[root].l == tree[root].r)
    131     {
    132         tree[root].maxv = tree[root].minv = v;
    133         tree[root].delay = 0;
    134         return;
    135     }
    136     PushDown(root);
    137     int mid = (tree[root].r + tree[root].l) / 2;
    138     if (l <= mid)Update(root * 2, l, r, v);
    139     if (r > mid)Update(root * 2 + 1, l, r, v);
    140     PushUp(root);
    141 }
    142 void Update_Neg(int root, int l, int r)
    143 {//取反
    144     if (tree[root].r<l || tree[root].l>r) return;
    145     if (l <= tree[root].l&&tree[root].r <= r)
    146     {
    147         tree[root].delay ^= 1;
    148         swap(tree[root].maxv, tree[root].minv);
    149         tree[root].maxv = -tree[root].maxv, tree[root].minv = -tree[root].minv;
    150         return;
    151     }
    152     PushDown(root);
    153     int mid = (tree[root].r + tree[root].l) / 2;
    154     if (l <= mid)Update_Neg(root * 2, l, r);
    155     if (r > mid)Update_Neg(root * 2 + 1, l, r);
    156     PushUp(root);
    157 }
    158 
    159 long long Query(int root, int l, int r)
    160 {
    161     if (tree[root].r<l || tree[root].l>r) return 0;
    162     if (l <= tree[root].l&&tree[root].r <= r)
    163     {
    164         return tree[root].maxv;
    165     }
    166     PushDown(root);
    167     long long ans = 0, tmp1, tmp2;
    168     bool flag1 = false, flag2 = false;
    169     int mid = (tree[root].l + tree[root].r) / 2;
    170     if (l <= mid) tmp1 = Query(root * 2, l, r), flag1 = true;
    171     if (r > mid) tmp2 = Query(root * 2 + 1, l, r), flag2 = true;
    172     PushUp(root);
    173     if (flag1&&flag2) ans = max(tmp1, tmp2);
    174     else if (flag2)ans = tmp2;
    175     else ans = tmp1;
    176     return ans;
    177 }
    178 /*-------线段树·终————*/
    179 
    180 long long Query_length(int x, int y)
    181 {//查询x到y路径上最大边权
    182     int fx = top[x], fy = top[y];
    183     long long ans = 0;
    184     bool flag = false;
    185     while (fx != fy)
    186     {
    187         if (dep[fx] > dep[fy])
    188         {
    189 
    190             int id1 = nid[fx], id2 = nid[x];
    191             long long tmp = Query(1, id1, id2);
    192             x = father[fx];
    193             fx = top[x];
    194             if (!flag) ans = tmp;
    195             else ans = max(ans, tmp);
    196             flag = true;
    197         }
    198         else
    199         {
    200             int id1 = nid[fy], id2 = nid[y];
    201             long long tmp = Query(1, id1, id2);
    202             y = father[fy];
    203             fy = top[y];
    204             if (!flag) ans = tmp;
    205             else ans = max(ans, tmp);
    206             flag = true;
    207         }
    208     }
    209     if (x != y)
    210     {
    211         if (dep[x] > dep[y])
    212         {
    213 
    214             int id1 = nid[son[y]], id2 = nid[x];
    215             long long tmp = Query(1, id1, id2);
    216             if (!flag) ans = tmp;
    217             else ans = max(ans, tmp);
    218             flag = true;
    219         }
    220         else
    221         {
    222             int id1 = nid[son[x]], id2 = nid[y];
    223             long long tmp = Query(1, id1, id2);
    224             if (!flag) ans = tmp;
    225             else ans = max(ans, tmp);
    226             flag = true;
    227         }
    228     }
    229     return ans;
    230 }
    231 void Update_path(int x, int y)
    232 {//将x到y路径上所有边的值都取反
    233     int fx = top[x], fy = top[y];
    234     while (fx != fy)
    235     {
    236         if (dep[fx] >= dep[fy])
    237         {
    238             Update_Neg(1, nid[fx], nid[x]);
    239             x = father[fx];
    240             fx = top[x];
    241         }
    242         else
    243         {
    244             Update_Neg(1, nid[fy], nid[y]);
    245             y = father[fy];
    246             fy = top[y];
    247         }
    248     }
    249     if (x != y)
    250     {
    251         if (dep[x] < dep[y]) Update_Neg(1, nid[son[x]], nid[y]);
    252         else Update_Neg(1, nid[son[y]], nid[x]);
    253     }
    254 }
    255 /*-------树链剖分·终-------*/
    256 
    257 int main()
    258 {
    259     int t;
    260     scanf("%d", &t);
    261     int n, m;
    262     while (t--)
    263     {
    264         INIT();
    265         scanf("%d", &n);
    266         for (int i = 1; i < n; i++)
    267         {
    268             int u, v, w;
    269             scanf("%d%d%d", &u, &v, &w);
    270             addEdge(u, v, w);
    271         }
    272         dfs1(1, 1, 1);
    273         dfs2(1, 1);
    274         BuildTree(1, 1, cnt);
    275         char s[10];
    276         while (true)
    277         {
    278             scanf("%s", s);
    279             if (s[0] == 'Q')
    280             {
    281                 int u, v;
    282                 scanf("%d%d", &u, &v);
    283                 long long ans = Query_length(u, v);
    284                 printf("%lld
    ", ans);
    285             }
    286             else if (s[0] == 'C')
    287             {
    288                 int id, v;
    289                 scanf("%d%d", &id, &v);
    290                 int nID = nid[linkto[id]];
    291                 Update(1, nID, nID, v);
    292             }
    293             else if (s[0] == 'N')
    294             {
    295                 int u, v;
    296                 scanf("%d%d", &u, &v);
    297                 Update_path(u, v);
    298             }
    299             else
    300             {
    301                 break;
    302             }
    303         }
    304     }
    305     return 0;
    306 }
    View Code
  • 相关阅读:
    函数
    向discuz里填充数据
    CI 基础
    FlashBuilder设置显示字符集
    win2003 Email邮件服务器搭配
    CI 模块化显示[仿照shopex功能]
    DW的鸟语
    CI 视图里加视图
    silverlight模拟单击事件
    自定义XML配置文件的操作类(转)
  • 原文地址:https://www.cnblogs.com/ivan-count/p/9358585.html
Copyright © 2011-2022 走看看