zoukankan      html  css  js  c++  java
  • POJ 3237 Tree (树链剖分)

    Tree
    Time Limit: 5000MS   Memory Limit: 131072K
    Total Submissions: 2825   Accepted: 769

    Description

    You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:

    CHANGE i v Change the weight of the ith edge to v
    NEGATE a b Negate the weight of every edge on the path from a to b
    QUERY a b Find the maximum weight of edges on the path from a to b

    Input

    The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.

    Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers ab and c, describing an edge connecting nodes a and b with weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE” ends the test case.

    Output

    For each “QUERY” instruction, output the result on a separate line.

    Sample Input

    1
    
    3
    1 2 1
    2 3 2
    QUERY 1 2
    CHANGE 1 3
    QUERY 1 2
    DONE

    Sample Output

    1
    3

    Source

    树链剖分+线段树实现

      1 /* ***********************************************
      2 Author        :kuangbin
      3 Created Time  :2013/8/17 4:04:42
      4 File Name     :F:2013ACM练习专题学习数链剖分POJ3237Tree.cpp
      5 ************************************************ */
      6 
      7 #include <stdio.h>
      8 #include <string.h>
      9 #include <iostream>
     10 #include <algorithm>
     11 #include <vector>
     12 #include <queue>
     13 #include <set>
     14 #include <map>
     15 #include <string>
     16 #include <math.h>
     17 #include <stdlib.h>
     18 #include <time.h>
     19 using namespace std;
     20 
     21 const int MAXN = 100010;
     22 struct Edge
     23 {
     24     int to,next;
     25 }edge[MAXN*2];
     26 int head[MAXN],tot;
     27 int top[MAXN];//top[v]表示v所在的重链的顶端节点
     28 int fa[MAXN]; //父亲节点
     29 int deep[MAXN];//深度
     30 int num[MAXN];//num[v]表示以v为根的子树的节点数
     31 int p[MAXN];//p[v]表示v与其父亲节点的连边在线段树中的位置
     32 int fp[MAXN];//和p数组相反
     33 int son[MAXN];//重儿子
     34 int pos;
     35 void init()
     36 {
     37     tot = 0;
     38     memset(head,-1,sizeof(head));
     39     pos = 0;
     40     memset(son,-1,sizeof(son));
     41 }
     42 void addedge(int u,int v)
     43 {
     44     edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;
     45 }
     46 void dfs1(int u,int pre,int d) //第一遍dfs求出fa,deep,num,son
     47 {
     48     deep[u] = d;
     49     fa[u] = pre;
     50     num[u] = 1;
     51     for(int i = head[u];i != -1; i = edge[i].next)
     52     {
     53         int v = edge[i].to;
     54         if(v != pre)
     55         {
     56             dfs1(v,u,d+1);
     57             num[u] += num[v];
     58             if(son[u] == -1 || num[v] > num[son[u]])
     59                 son[u] = v;
     60         }
     61     }
     62 }
     63 void getpos(int u,int sp) //第二遍dfs求出top和p
     64 {
     65     top[u] = sp;
     66     p[u] = pos++;
     67     fp[p[u]] = u;
     68     if(son[u] == -1) return;
     69     getpos(son[u],sp);
     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 != fa[u])
     74             getpos(v,v);
     75     }
     76 }
     77 
     78 //线段树
     79 struct Node
     80 {
     81     int l,r;
     82     int Max;
     83     int Min;
     84     int ne;
     85 }segTree[MAXN*3];
     86 void build(int i,int l,int r)
     87 {
     88     segTree[i].l = l;
     89     segTree[i].r = r;
     90     segTree[i].Max = 0;
     91     segTree[i].Min = 0;
     92     segTree[i].ne = 0;
     93     if(l == r)return;
     94     int mid = (l+r)/2;
     95     build(i<<1,l,mid);
     96     build((i<<1)|1,mid+1,r);
     97 }
     98 void push_up(int i)
     99 {
    100     segTree[i].Max = max(segTree[i<<1].Max,segTree[(i<<1)|1].Max);
    101     segTree[i].Min = min(segTree[i<<1].Min,segTree[(i<<1)|1].Min);
    102 }
    103 void push_down(int i)
    104 {
    105     if(segTree[i].l == segTree[i].r)return;
    106     if(segTree[i].ne)
    107     {
    108         segTree[i<<1].Max = -segTree[i<<1].Max;
    109         segTree[i<<1].Min = -segTree[i<<1].Min;
    110         swap(segTree[i<<1].Min,segTree[i<<1].Max);
    111         segTree[(i<<1)|1].Max = -segTree[(i<<1)|1].Max;
    112         segTree[(i<<1)|1].Min = -segTree[(i<<1)|1].Min;
    113         swap(segTree[(i<<1)|1].Max,segTree[(i<<1)|1].Min);
    114         segTree[i<<1].ne ^= 1;
    115         segTree[(i<<1)|1].ne ^= 1;
    116         segTree[i].ne = 0;
    117     }
    118 }
    119 void update(int i,int k,int val) // 更新线段树的第k个值为val
    120 {
    121     if(segTree[i].l == k && segTree[i].r == k)
    122     {
    123         segTree[i].Max = val;
    124         segTree[i].Min = val;
    125         segTree[i].ne = 0;
    126         return;
    127     }
    128     push_down(i);
    129     int mid = (segTree[i].l + segTree[i].r)/2;
    130     if(k <= mid)update(i<<1,k,val);
    131     else update((i<<1)|1,k,val);
    132     push_up(i);
    133 }
    134 void ne_update(int i,int l,int r) // 更新线段树的区间[l,r]取反
    135 {
    136     if(segTree[i].l == l && segTree[i].r == r)
    137     {
    138         segTree[i].Max = -segTree[i].Max;
    139         segTree[i].Min = -segTree[i].Min;
    140         swap(segTree[i].Max,segTree[i].Min);
    141         segTree[i].ne ^= 1;
    142         return;
    143     }
    144     push_down(i);
    145     int mid = (segTree[i].l + segTree[i].r)/2;
    146     if(r <= mid)ne_update(i<<1,l,r);
    147     else if(l > mid) ne_update((i<<1)|1,l,r);
    148     else
    149     {
    150         ne_update(i<<1,l,mid);
    151         ne_update((i<<1)|1,mid+1,r);
    152     }
    153     push_up(i);
    154 }
    155 int query(int i,int l,int r)  //查询线段树中[l,r] 的最大值
    156 {
    157     if(segTree[i].l == l && segTree[i].r == r)
    158         return segTree[i].Max;
    159     push_down(i);
    160     int mid = (segTree[i].l + segTree[i].r)/2;
    161     if(r <= mid)return query(i<<1,l,r);
    162     else if(l > mid)return query((i<<1)|1,l,r);
    163     else return max(query(i<<1,l,mid),query((i<<1)|1,mid+1,r));
    164     push_up(i);
    165 }
    166 int findmax(int u,int v)//查询u->v边的最大值
    167 {
    168     int f1 = top[u], f2 = top[v];
    169     int tmp = -100000000;
    170     while(f1 != f2)
    171     {
    172         if(deep[f1] < deep[f2])
    173         {
    174             swap(f1,f2);
    175             swap(u,v);
    176         }
    177         tmp = max(tmp,query(1,p[f1],p[u]));
    178         u = fa[f1]; f1 = top[u];
    179     }
    180     if(u == v)return tmp;
    181     if(deep[u] > deep[v]) swap(u,v);
    182     return max(tmp,query(1,p[son[u]],p[v]));
    183 }
    184 void Negate(int u,int v)//把u-v路径上的边的值都设置为val
    185 {
    186     int f1 = top[u], f2 = top[v];
    187     while(f1 != f2)
    188     {
    189         if(deep[f1] < deep[f2])
    190         {
    191             swap(f1,f2);
    192             swap(u,v);
    193         }
    194         ne_update(1,p[f1],p[u]);
    195         u = fa[f1]; f1 = top[u];
    196     }
    197     if(u == v)return;
    198     if(deep[u] > deep[v]) swap(u,v);
    199     return ne_update(1,p[son[u]],p[v]);
    200 }
    201 int e[MAXN][3];
    202 int main()
    203 {
    204     //freopen("in.txt","r",stdin);
    205     //freopen("out.txt","w",stdout);
    206     int T;
    207     int n;
    208     scanf("%d",&T);
    209     while(T--)
    210     {
    211         init();
    212         scanf("%d",&n);
    213         for(int i = 0;i < n-1;i++)
    214         {
    215             scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
    216             addedge(e[i][0],e[i][1]);
    217             addedge(e[i][1],e[i][0]);
    218         }
    219         dfs1(1,0,0);
    220         getpos(1,1);
    221         build(1,0,pos-1);
    222         for(int i = 0;i < n-1; i++)
    223         {
    224             if(deep[e[i][0]] > deep[e[i][1]])
    225                 swap(e[i][0],e[i][1]);
    226             update(1,p[e[i][1]],e[i][2]);
    227         }
    228         char op[10];
    229         int u,v;
    230         while(scanf("%s",op) == 1)
    231         {
    232             if(op[0] == 'D')break;
    233             scanf("%d%d",&u,&v);
    234             if(op[0] == 'Q')
    235                 printf("%d
    ",findmax(u,v));//查询u->v路径上边权的最大值
    236             else if(op[0] == 'C')
    237                 update(1,p[e[u-1][1]],v);//改变第u条边的值为v
    238             else Negate(u,v);
    239         }
    240     }
    241     return 0;
    242 }
  • 相关阅读:
    vc 获得文件相对路径
    C#关闭MessageBox消息框(转)
    ip地址及地理位置查询
    WinDbg关联dump文件
    国外程序员推荐:每个程序员都应读的书
    [转]史上最全的C位域总结201036 2:58:00
    android 屏幕保持唤醒 不锁屏
    [转]win7如何共享
    一些DirectUI方面的资料
    计算器程序,可以计算正实数范围内的任何数据的加减乘除括号,混合运算
  • 原文地址:https://www.cnblogs.com/kuangbin/p/3263822.html
Copyright © 2011-2022 走看看