• POJ 3237.Tree -树链剖分(边权)(边值更新、路径边权最值、区间标记)贴个板子备忘


    Time Limit: 5000MS   Memory Limit: 131072K
    Total Submissions: 12247   Accepted: 3151

    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

     
     
     

    题意就是: 有T组数据 ,给你n个点的树,有三种操作:

     1.CHANGE i v :将第i条边的值改为v   

     2.NEGATE a b :将a点到b点路径上的边权取反      

    3.QUERY a b :查询a点到b点路径上最大的边权值,

    由于有取反操作,记录最大和最小值 然后取反并交换就可以,用线段树来维护,真香警告。。。

    代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<bitset>
      6 #include<cassert>
      7 #include<cctype>
      8 #include<cmath>
      9 #include<cstdlib>
     10 #include<ctime>
     11 #include<deque>
     12 #include<iomanip>
     13 #include<list>
     14 #include<map>
     15 #include<queue>
     16 #include<set>
     17 #include<stack>
     18 #include<vector>
     19 using namespace std;
     20 typedef long long ll;
     21 
     22 const double PI=acos(-1.0);
     23 const double eps=1e-6;
     24 const ll mod=1e9+7;
     25 const int inf=0x3f3f3f3f;
     26 const int maxn=1e4+10;
     27 const int maxm=100+10;
     28 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     29 #define lson l,m,rt<<1
     30 #define rson m+1,r,rt<<1|1
     31 
     32 int head[maxn],cnt,num,n;
     33 
     34 struct Edge{
     35     int to,next;
     36 }edge[maxn<<1];
     37 
     38 void add(int u,int v)//存图(树)
     39 {
     40     edge[cnt].to=v;
     41     edge[cnt].next=head[u];
     42     head[u]=cnt++;
     43 }
     44 
     45 int val[maxn],siz[maxn],dep[maxn],son[maxn];
     46 int top[maxn],tid[maxn],pos[maxn],fa[maxn];
     47 
     48 void init()//初始化
     49 {
     50     memset(head,-1,sizeof(head));
     51     memset(son,-1,sizeof(son));
     52     cnt=num=0;
     53 }
     54 
     55 ///树链剖分部分
     56 void dfs1(int u,int father)//第一遍dfs,可以得到当前节点的父亲节点,当前节点的深度,当前节点的重儿子
     57 {
     58     //更新dep,fa,siz数组
     59     siz[u]=1;//保存以u为根的子树节点个数
     60     fa[u]=father;//保存爸爸
     61     dep[u]=dep[father]+1;//记录深度
     62     for(int i=head[u];~i;i=edge[i].next){//遍历所有和当前节点连接的节点
     63         int v=edge[i].to;
     64         if(v!=father){//如果连接的是当前节点的父亲节点,则不处理
     65             dfs1(v,u);
     66             siz[u]+=siz[v];//直接子树节点相加,当前节点的size加上子节点的size
     67             if(son[u]==-1||siz[v]>siz[son[u]])//如果没有设置过重节点son或者子节点v的size大于之前记录的重节点son,进行更新
     68                 son[u]=v;//保存重儿子
     69         }
     70     }
     71 }
     72 
     73 void dfs2(int u,int tp)//将各个重节点连接成重链,轻节点连接成轻链,并且将重链(区间)用数据结构(一般是树状数组或者线段树)来维护,并且为每个节点进行编号,其实就是dfs在执行时的顺序(tid数组),以及当前节点所在链的起点(top数组)还有当前节点在树中的位置(pos)                                                                                                                                                                                                                                                                                                                                                          )
     74 {
     75     top[u]=tp;//保存当前节点所在的链的顶端节点,当前节点的起点
     76     tid[u]=++num;//保存树中每个节点剖分以后的新编号(dfs的执行顺序)
     77     pos[tid[u]]=u;//保存当前节点在树中的位置,设置dfs序号对应成当前节点
     78     if(son[u]==-1) return ;//如果当前节点没有处在重链上,则不处理
     79     dfs2(son[u],tp);//将这条重链上的所有节点都设置成起始的重节点
     80     for(int i=head[u];~i;i=edge[i].next){//遍历所有和当前节点连接的节点
     81         int v=edge[i].to;//如果连接节点不是当前节点的重节点并且也不是u的父节点,则将其的top设置成自己,进一步递归
     82         if(v!=son[u]&&v!=fa[u])
     83             dfs2(v,v);
     84     }
     85 }
     86 
     87 int lazy[maxn<<2],Max[maxn<<2],Min[maxn<<2];
     88 
     89 //线段树部分
     90 void Swap(int &x,int &y){int t=x;x=-y;y=-t;}
     91 
     92 void pushup(int rt)
     93 {
     94     Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
     95     Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
     96 }
     97 
     98 void pushdown(int rt)
     99 {
    100     if(lazy[rt]){
    101         lazy[rt<<1]+=lazy[rt];
    102         lazy[rt<<1|1]+=lazy[rt];
    103         if(lazy[rt]&1){ //两个子区间是否取反依靠当前区间的懒惰标记判断,判断奇偶
    104             Swap(Max[rt<<1],Min[rt<<1]);
    105             Swap(Max[rt<<1|1],Min[rt<<1|1]);
    106         }
    107         lazy[rt]=0;
    108     }
    109 }
    110 
    111 void build(int l,int r,int rt)
    112 {
    113     lazy[rt]=0;
    114     if(l==r){
    115         Max[rt]=Min[rt]=0;
    116         return ;
    117     }
    118 
    119     int m=(l+r)>>1;
    120     build(lson);
    121     build(rson);
    122     pushup(rt);
    123 }
    124 
    125 void update(int pos,int val,int l,int r,int rt)
    126 {
    127     if(l==r&&l==pos){
    128         Max[rt]=val;Min[rt]=val;lazy[rt]=0;
    129         return ;
    130     }
    131 
    132     pushdown(rt);
    133     int m=(l+r)>>1;
    134     if(pos<=m) update(pos,val,lson);
    135     else       update(pos,val,rson);
    136     pushup(rt);
    137 }
    138 
    139 void Negate(int L,int R,int l,int r,int rt)//Negate是int tmp=Max,Max=-Min,Min=-tmp
    140 {
    141     if(L<=l&&r<=R){
    142         lazy[rt]++;
    143         Swap(Max[rt],Min[rt]);//这里要马上取反
    144         return ;
    145     }
    146 
    147     pushdown(rt);
    148     int m=(l+r)>>1;
    149     if(L<=m) Negate(L,R,lson);
    150     if(R> m) Negate(L,R,rson);
    151     pushup(rt);
    152 }
    153 
    154 int query(int L,int R,int l,int r,int rt)
    155 {
    156     if(L<=l&&r<=R){
    157         return Max[rt];
    158     }
    159 
    160     pushdown(rt);
    161     int ret=-inf;
    162     int m=(l+r)>>1;
    163     if(L<=m) ret=max(ret,query(L,R,lson));
    164     if(R> m) ret=max(ret,query(L,R,rson));
    165     pushup(rt);
    166     return ret;
    167 }
    168 
    169 int get_max(int u,int v)
    170 {
    171     int ans=-1<<30;
    172     while(top[u]!=top[v]){
    173         if(dep[top[u]]<dep[top[v]]) swap(u,v);
    174         ans=max(ans,query(tid[top[u]],tid[u],1,n,1));
    175         u=fa[top[u]];
    176     }
    177 
    178     if(dep[v]<dep[u]) swap(u,v);
    179     ans=max(ans,query(tid[son[u]],tid[v],1,n,1));//这里写捞了,tid[son[u]],写成tid[u],wa了好几天。。。
    180     printf("%d
    ",ans);
    181 }
    182 
    183 void change(int u,int v)
    184 {
    185     while(top[u]!=top[v]){
    186         if(dep[top[u]]<dep[top[v]]) swap(u,v);
    187         Negate(tid[top[u]],tid[u],1,n,1);
    188         u=fa[top[u]];
    189     }
    190 
    191     if(u==v) return ;
    192     if(dep[v]<dep[u]) swap(u,v);
    193     Negate(tid[son[u]],tid[v],1,n,1);
    194 }
    195 
    196 struct eg{
    197     int u,v,val;
    198 }eg[maxn];
    199 
    200 int main()
    201 {
    202     int t;
    203     scanf("%d",&t);
    204     while(t--){
    205         scanf("%d",&n);
    206         init();
    207         for(int i=1;i<n;i++){
    208             scanf("%d%d%d",&eg[i].u,&eg[i].v,&eg[i].val);
    209             add(eg[i].u,eg[i].v);//加边
    210             add(eg[i].v,eg[i].u);//加边
    211         }
    212         dfs1(1,0);//第一遍dfs
    213         dfs2(1,1);//第二遍dfs
    214         build(1,n,1);
    215         for(int i=1;i<n;i++){
    216             if(dep[eg[i].u]<dep[eg[i].v]) swap(eg[i].u,eg[i].v);
    217             update(tid[eg[i].u],eg[i].val,1,n,1);
    218         }
    219         int a,b;
    220         char op[10];
    221         while(scanf("%s",op)&&op[0]!='D'){
    222             scanf("%d%d",&a,&b);
    223             if(op[0]=='Q'){
    224                 get_max(a,b);
    225             }
    226             if(op[0]=='C'){
    227                 update(tid[eg[a].u],b,1,n,1);
    228             }
    229             if(op[0]=='N'){
    230                 change(a,b);
    231             }
    232         }
    233     }
    234 }

    哈哈哈哈,加油加油。

  • 相关阅读:
    POJ 3280 Cheapest Palindrome (区间DP)
    UVaLive 4731 Cellular Network (期望DP)
    UVa 11404 Palindromic Subsequence (LCS)
    UVa 11552 Fewest Flops (DP)
    UVa 10534 Wavio Sequence (LIS+暴力)
    UVaLive 4256 Salesmen (简单DP)
    UVaLive 4094 WonderTeam (贪心)
    UVaLive 3266 Tian Ji -- The Horse Racing (贪心)
    POJ 3723 Conscription (最小生成树)
    NodeJS学习笔记 进阶 (4)基于express+muter的文件上传(ok)
  • 原文地址:https://www.cnblogs.com/ZERO-/p/9670796.html
Copyright © 2020-2023  润新知