• BZOJ3999:[TJOI2015]旅游(树链剖分)


    Description

    为了提高智商,ZJY准备去往一个新世界去旅游。这个世界的城市布局像一棵树。每两座城市之间只有一条路径可
    以互达。每座城市都有一种宝石,有一定的价格。ZJY为了赚取最高利益,她会选择从A城市买入再转手卖到B城市
    。由于ZJY买宝石时经常卖萌,因而凡是ZJY路过的城市,这座城市的宝石价格会上涨。让我们来算算ZJY旅游完之
    后能够赚取的最大利润。(如a城市宝石价格为v,则ZJY出售价格也为v)

    Input

    第一行输入一个正整数N,表示城市个数。
    接下来一行输入N个正整数表示每座城市宝石的最初价格p,每个宝石的初始价格不超过100。
    第三行开始连续输入N-1行,每行有两个数字x和y。表示x城市和y城市有一条路径。城市编号从1开始。
    下一行输入一个整数Q,表示询问次数。
    接下来Q行,每行输入三个正整数a,b,v,表示ZJY从a旅游到b,城市宝石上涨v。
    1≤ N≤50000, 1≤Q ≤50000

    Output

     对于每次询问,输出ZJY可能获得的最大利润,如果亏本则输出0。

    Sample Input

    3
    1 2 3
    1 2
    2 3
    2
    1 2 100
    1 3 100

    Sample Output

    1
    1

    Solution

    不拍一下还真不知道自己错了不少细节
    对拍+debug使我快乐
    一开始把题给读错了……
    对于这个题,我们要做的就是查询路径上的最大差值(max-min)。
    然后就很容易想到用树链剖分维护。
    不过这个是有限制的,即在路径上,min必须出现在max前面。
    怎么办呢?我们可以分两种情况来考虑。
    1、max,min出现在一段完整的重链中。这个我们可以用线段树上的标记很好的维护。
    维护一个ans1一个ans2,分别表示不同方向时这一段内的最大差值。(看一下pushup函数就懂了)
    2、max,min出现在不同的链中
    我们往上跳的时候,按顺序记录一下我们路径经过的轻重链的信息。
    跳完之后扫一遍更新答案即可。
    细节挺多的反正我拍挂了很多次

    Code

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<queue>
      5 #define N (50000+100)
      6 using namespace std;
      7 
      8 struct segt{int val,add,max,min,ans1,ans2;}Segt[N<<2],refun[N];
      9 struct node{int to,next;}edge[N<<1];
     10 int n,m,a[N],u,v,l,ans;
     11 int head[N],num_edge;
     12 int Father[N],Depth[N],Son[N],Sum[N];
     13 int T_num[N],Tree[N],Top[N],dfs_num;
     14 queue<segt>q[2];
     15 
     16 void add(int u,int v)
     17 {
     18     edge[++num_edge].to=v;
     19     edge[num_edge].next=head[u];
     20     head[u]=num_edge;
     21 }
     22 
     23 void Dfs1(int x) 
     24 {
     25     Sum[x]=1;
     26     Depth[x]=Depth[Father[x]]+1;
     27     for (int i=head[x]; i; i=edge[i].next)
     28         if (edge[i].to!=Father[x])
     29         {
     30             Father[edge[i].to]=x;
     31             Dfs1(edge[i].to);
     32             Sum[x]+=Sum[edge[i].to];
     33             if (!Son[x] || Sum[Son[x]]<Sum[edge[i].to])
     34                 Son[x]=edge[i].to;
     35         }
     36 }
     37 
     38 void Dfs2(int x,int pre)
     39 {
     40     T_num[x]=++dfs_num;
     41     Tree[dfs_num]=a[x];
     42     Top[x]=pre;
     43     if (Son[x]) Dfs2(Son[x],pre);
     44     for (int i=head[x]; i; i=edge[i].next)
     45         if (edge[i].to!=Father[x] && edge[i].to!=Son[x])
     46             Dfs2(edge[i].to,edge[i].to);
     47 }
     48 
     49 void Pushdown(int now,int l,int r)
     50 {
     51     if (Segt[now].add)
     52     {
     53         int mid=(l+r)>>1;
     54         Segt[now<<1].add+=Segt[now].add;
     55         Segt[now<<1].val+=Segt[now].add*(mid-l+1);
     56         Segt[now<<1|1].add+=Segt[now].add;
     57         Segt[now<<1|1].val+=Segt[now].add*(r-mid);
     58         Segt[now<<1].max+=Segt[now].add;
     59         Segt[now<<1].min+=Segt[now].add;
     60         Segt[now<<1|1].max+=Segt[now].add;
     61         Segt[now<<1|1].min+=Segt[now].add;//一开始max和min忘记更新*%……%&* 
     62         Segt[now].add=0;
     63     }
     64 }
     65 
     66 segt Pushup(int x,segt ls,segt rs)//pushup返回类型改一下方便处理 
     67 {
     68     segt now=Segt[x];
     69     now.val=ls.val+rs.val;
     70     now.max=max(ls.max,rs.max);
     71     now.min=min(ls.min,rs.min);
     72     now.ans1=max(ls.ans1,rs.ans1);
     73     now.ans1=max(now.ans1,rs.max-ls.min);
     74     now.ans2=max(ls.ans2,rs.ans2);
     75     now.ans2=max(now.ans2,ls.max-rs.min);
     76     return now;
     77 }
     78 
     79 void Build(int now,int l,int r)
     80 {
     81     if (l==r){Segt[now].val=Segt[now].max=Segt[now].min=Tree[l];return;}
     82     int mid=(l+r)>>1;
     83     Build(now<<1,l,mid); Build(now<<1|1,mid+1,r);
     84     Segt[now]=Pushup(now,Segt[now<<1],Segt[now<<1|1]);
     85 }
     86 
     87 void Update(int now,int l,int r,int l1,int r1,int k) 
     88 {
     89     if (l>r1 || r<l1) return;
     90     if (l1<=l && r<=r1)
     91     {
     92         Segt[now].val+=(r-l+1)*k;
     93         Segt[now].add+=k;
     94         Segt[now].max+=k;
     95         Segt[now].min+=k;
     96         return;
     97     }
     98     Pushdown(now,l,r);
     99     int mid=(l+r)>>1;
    100     Update(now<<1,l,mid,l1,r1,k);Update(now<<1|1,mid+1,r,l1,r1,k);
    101     Segt[now]=Pushup(now,Segt[now<<1],Segt[now<<1|1]);
    102 }
    103 
    104 segt Query(int now,int l,int r,int l1,int r1)
    105 {
    106     if (l1<=l && r<=r1)
    107         return Segt[now];
    108     Pushdown(now,l,r);
    109     int mid=(l+r)>>1;
    110     if (r1<=mid) return Query(now<<1,l,mid,l1,r1);
    111     if (l1>=mid+1) return Query(now<<1|1,mid+1,r,l1,r1);
    112     return Pushup(now,Query(now<<1,l,mid,l1,r1),Query(now<<1|1,mid+1,r,l1,r1));
    113 }
    114 
    115 void Change(int x,int y,int k)
    116 {
    117     int fx=Top[x],fy=Top[y];
    118     while (fx!=fy)
    119     {
    120         if (Depth[fx]<Depth[fy])
    121             swap(x,y),swap(fx,fy);
    122         Update(1,1,n,T_num[fx],T_num[x],k);
    123         x=Father[fx],fx=Top[x];
    124     }
    125     if (Depth[x]<Depth[y]) swap(x,y);
    126     Update(1,1,n,T_num[y],T_num[x],k);
    127 }
    128 
    129 int Ask(int x,int y)//主要就是这个函数里的问题,我开了两个queue来记录路径。 
    130 {
    131     int fx=Top[x],fy=Top[y];
    132     int now=0,ans=0,cnt=0,h=0,sum;
    133     while (fx!=fy)
    134     {
    135         if (Depth[fx]<Depth[fy])
    136             swap(x,y),swap(fx,fy),now^=1;
    137         segt no=Query(1,1,n,T_num[fx],T_num[x]);
    138         q[now].push(no); cnt++;
    139         ans=max(ans,now==1?no.ans1:no.ans2);
    140         x=Father[fx],fx=Top[x];
    141     }
    142     if (Depth[x]<Depth[y]) swap(x,y),now^=1;
    143     segt no=Query(1,1,n,T_num[y],T_num[x]);
    144     ans=max(ans,now==1?no.ans1:no.ans2);
    145     q[now].push(no); cnt++;
    146     sum=cnt;
    147     
    148     while (!q[0].empty()) refun[++h]=q[0].front(),q[0].pop();
    149     while (!q[1].empty()) refun[cnt--]=q[1].front(),q[1].pop();
    150     int minn=refun[1].min;
    151     for (int i=2; i<=sum; ++i)//扫一遍路径上的链,然后更新一下。 
    152     {
    153         ans=max(ans,refun[i].max-minn);
    154         minn=min(minn,refun[i].min);//一开始这里忘了更新了#¥%#¥*& 
    155     }
    156     return ans;
    157 }
    158 
    159 int main()
    160 {
    161     scanf("%d",&n);
    162     for (int i=1; i<=n; ++i)
    163         scanf("%d",&a[i]);
    164     for (int i=1; i<=n-1; ++i)
    165     {
    166         scanf("%d%d",&u,&v);
    167         add(u,v); add(v,u);
    168     }
    169     Dfs1(1); Dfs2(1,1); 
    170     Build(1,1,n);
    171     scanf("%d",&m);
    172     for (int i=1; i<=m; ++i)
    173     {
    174         scanf("%d%d%d",&u,&v,&l);
    175         int ans=Ask(u,v);
    176         printf("%d
    ",ans>0?ans:0);
    177         Change(u,v,l);
    178     }
    179 }
  • 相关阅读:
    三数之和
    167
    二分搜索树
    687
    索引堆
    二分查找 leetcode704
    leetcode 56合并区间 java
    leetcode 1046
    堆的数据结构java
    leetcode 493
  • 原文地址:https://www.cnblogs.com/refun/p/8970616.html
Copyright © 2020-2023  润新知