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

    题目链接:http://poj.org/problem?id=3237

    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

    题意描述:一棵树有n个节点和n-1条边,每条边有一个权值。现在给出三种操作:

    CHANGE I V:把第i条边的值改为v

    NEGATE A B:把A到B的路径上的所有边的值取反(正为负,负改为正)

    QUERY A B:询问A到B的路径上的边权值的最大值。

    算法分析:树链剖分解决。把边权值移到节点上面,由于操作上有对值取反,所有我们不止要运用线段树统计区间最大值maxnum,还要统计区间最小值minnum,这样在取反操作后,maxnum=-maxnum,minnum=-minnum,再把两个值交换:swap(maxnum,minnum)即可。

    说明:阅读了一些大牛的代码,感觉线段树部分还是结构体比数组方便一些,树链剖分刚开始学,代码和解题思想很多是借鉴大牛们的,只是把代码风格改成自己的了,相信只有不断学习和解题才会对树链剖分有一定理解的。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<cmath>
      6 #include<algorithm>
      7 #include<vector>
      8 #define inf 0x7fffffff
      9 using namespace std;
     10 const int maxn=100000+10;
     11 
     12 struct Edge
     13 {
     14     int to,next;
     15 }edge[maxn*2];
     16 int head[maxn],edgenum;
     17 int top[maxn];//top[v]表示v所在的重链的顶端节点
     18 int fa[maxn]; //父亲节点
     19 int dep[maxn];//深度
     20 int siz[maxn];//siz[v]表示以v为根的子树的节点数
     21 int tid[maxn];//tid[v]表示v与其父亲节点的连边在线段树中的位置
     22 int tid2[maxn];//和tid数组相反
     23 int son[maxn];//重儿子
     24 int pos;
     25 void init()
     26 {
     27     edgenum=0;
     28     memset(head,-1,sizeof(head));
     29     pos=0;
     30     memset(son,-1,sizeof(son));
     31 }
     32 void addedge(int u,int v)
     33 {
     34     edge[edgenum].to=v ;edge[edgenum].next=head[u];
     35     head[u]=edgenum++;
     36 
     37     edge[edgenum].to=u ;edge[edgenum].next=head[v];
     38     head[v]=edgenum++;
     39 }
     40 
     41 void dfs1(int u,int pre,int d) //第一遍dfs求出fa,dep,siz,son
     42 {
     43     dep[u]=d;
     44     fa[u]=pre;
     45     siz[u]=1;
     46     for (int i=head[u] ;i != -1 ;i=edge[i].next)
     47     {
     48         int v=edge[i].to;
     49         if (v != pre)
     50         {
     51             dfs1(v,u,d+1);
     52             siz[u] += siz[v];
     53             if (son[u] == -1 || siz[v]>siz[son[u]])
     54                 son[u]=v;
     55         }
     56     }
     57 }
     58 void dfs2(int u,int tp) //第二遍dfs求出top和tid
     59 {
     60     top[u]=tp;
     61     tid[u]= ++pos;
     62     tid2[pos]=u;
     63     if (son[u] == -1) return;
     64     dfs2(son[u],tp);
     65     for (int i=head[u] ;i != -1 ;i=edge[i].next)
     66     {
     67         int v=edge[i].to;
     68         if (v != son[u] && v != fa[u])
     69             dfs2(v,v);
     70     }
     71 }
     72 
     73 //线段树
     74 struct node
     75 {
     76     int l,r;
     77     int Max;
     78     int Min;
     79     int ne;
     80 }segTree[maxn*3];
     81 
     82 void build(int l,int r,int rt)
     83 {
     84     segTree[rt].l=l;
     85     segTree[rt].r=r;
     86     segTree[rt].Max=0;
     87     segTree[rt].Min=0;
     88     segTree[rt].ne=0;
     89     if (l==r) return ;
     90     int mid=(l+r)/2;
     91     build(l,mid,rt<<1);
     92     build(mid+1,r,rt<<1|1);
     93 }
     94 void PushUP(int rt)
     95 {
     96     segTree[rt].Max = max(segTree[rt<<1].Max,segTree[rt<<1|1].Max);
     97     segTree[rt].Min = min(segTree[rt<<1].Min,segTree[rt<<1|1].Min);
     98 }
     99 void PushDown(int rt)
    100 {
    101     if (segTree[rt].l == segTree[rt].r) return ;
    102     if (segTree[rt].ne)
    103     {
    104         segTree[rt<<1].Max = -segTree[rt<<1].Max;
    105         segTree[rt<<1].Min = -segTree[rt<<1].Min;
    106         swap(segTree[rt<<1].Min,segTree[rt<<1].Max);
    107         segTree[rt<<1|1].Max = -segTree[rt<<1|1].Max;
    108         segTree[rt<<1|1].Min = -segTree[rt<<1|1].Min;
    109         swap(segTree[rt<<1|1].Max,segTree[rt<<1|1].Min);
    110         segTree[rt<<1].ne ^= 1;
    111         segTree[rt<<1|1].ne ^= 1;
    112         segTree[rt].ne = 0;
    113     }
    114 }
    115 
    116 void update(int k,int val,int rt) // 更新线段树的第k个值为val
    117 {
    118     if(segTree[rt].l == k && segTree[rt].r == k)
    119     {
    120         segTree[rt].Max = val;
    121         segTree[rt].Min = val;
    122         segTree[rt].ne = 0;
    123         return;
    124     }
    125     PushDown(rt);
    126     int mid = (segTree[rt].l + segTree[rt].r)/2;
    127     if(k <= mid)update(k,val,rt<<1);
    128     else update(k,val,(rt<<1)|1);
    129     PushUP(rt);
    130 }
    131 void ne_update(int l,int r,int rt) // 更新线段树的区间[l,r]取反
    132 {
    133     if (segTree[rt].l == l && segTree[rt].r == r)
    134     {
    135         segTree[rt].Max = -segTree[rt].Max;
    136         segTree[rt].Min = -segTree[rt].Min;
    137         swap(segTree[rt].Max,segTree[rt].Min);
    138         segTree[rt].ne ^= 1;
    139         return;
    140     }
    141     PushDown(rt);
    142     int mid = (segTree[rt].l + segTree[rt].r)/2;
    143     if (r <= mid) ne_update(l,r,rt<<1);
    144     else if (l > mid) ne_update(l,r,(rt<<1)|1);
    145     else
    146     {
    147         ne_update(l,mid,rt<<1);
    148         ne_update(mid+1,r,(rt<<1)|1);
    149     }
    150     PushUP(rt);
    151 }
    152 int query(int l,int r,int rt)  //查询线段树中[l,r] 的最大值
    153 {
    154     if (segTree[rt].l == l && segTree[rt].r == r)
    155         return segTree[rt].Max;
    156     PushDown(rt);
    157     int mid = (segTree[rt].l+segTree[rt].r)>>1;
    158     if (r <= mid) return query(l,r,rt<<1);
    159     else if (l > mid) return query(l,r,(rt<<1)|1);
    160     else return max(query(l,mid,rt<<1),query(mid+1,r,(rt<<1)|1));
    161     PushUP(rt);
    162 }
    163 int findmax(int u,int v)//查询u->v边的最大值
    164 {
    165     int f1 = top[u], f2 = top[v];
    166     int tmp = -100000000;
    167     while(f1 != f2)
    168     {
    169         if(dep[f1] < dep[f2])
    170         {
    171             swap(f1,f2);
    172             swap(u,v);
    173         }
    174         tmp = max(tmp,query(tid[f1],tid[u],1));
    175         u = fa[f1]; f1 = top[u];
    176     }
    177     if(u == v)return tmp;
    178     if(dep[u] > dep[v]) swap(u,v);
    179     return max(tmp,query(tid[son[u]],tid[v],1));
    180 }
    181 
    182 void Negate(int u,int v)
    183 {
    184     int f1=top[u],f2=top[v];
    185     while (f1 != f2)
    186     {
    187         if (dep[f1]<dep[f2])
    188         {
    189             swap(f1,f2);
    190             swap(u,v);
    191         }
    192         ne_update(tid[f1],tid[u],1);
    193         u=fa[f1] ;f1=top[u];
    194     }
    195     if (u==v) return;
    196     if (dep[u]>dep[v]) swap(u,v);
    197     return ne_update(tid[son[u] ],tid[v],1);
    198 }
    199 
    200 int e[maxn][3];
    201 int main()
    202 {
    203     int T;
    204     int n;
    205     scanf("%d",&T);
    206     while(T--)
    207     {
    208         init();
    209         scanf("%d",&n);
    210         for(int i = 0;i < n-1;i++)
    211         {
    212             scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
    213             addedge(e[i][0],e[i][1]);
    214         }
    215         dfs1(1,0,0);
    216         dfs2(1,1);
    217         build(1,n,1);
    218         for (int i = 0;i < n-1; i++)
    219         {
    220             if (dep[e[i][0]]>dep[e[i][1]])
    221                 swap(e[i][0],e[i][1]);
    222             update(tid[e[i][1]],e[i][2],1);
    223         }
    224         char op[10];
    225         int u,v;
    226         while (scanf("%s",op) == 1)
    227         {
    228             if (op[0] == 'D') break;
    229             scanf("%d%d",&u,&v);
    230             if (op[0]=='Q')
    231                 printf("%d
    ",findmax(u,v));//查询u->v路径上边权的最大值
    232             else if (op[0]=='C')
    233                 update(tid[e[u-1][1]],v,1);//改变第u条边的值为v
    234             else Negate(u,v);
    235         }
    236     }
    237     return 0;
    238 }
  • 相关阅读:
    JS基础算法题(一)
    JS数组的迭代器方法
    使用IcoMoon制作字体图标
    CSS浮动属性
    使用hibnate向数据库写入图片对象
    hibernate_基本配置和初始化步骤
    ORM框架
    Jsp中的session
    mysql的自我复制
    分页技术
  • 原文地址:https://www.cnblogs.com/huangxf/p/4345123.html
Copyright © 2011-2022 走看看