BZOJ3999

news/2024/7/4 13:00:48

来自蒟蒻XXJ的做题记录

其实这个题目就是一个比较裸的树剖w然后再加上一个线段树维护

首先看题目我们要解决的是一个求解区间里两个数之间差的最大值【绕

而且我们发现这两个数的关系还必须在路径上是有向的,也就是说必须是一个后走到的点减去一个先走到的点【雾

【树剖应该不用我说了吧 =w=

现在我们用线段树维护这样的四个量:

从编号小的向编号大的走可以得到的最大利润 lans

从编号大的向编号小的走可以得到的最大利润 rans

区间最大值 imax

区间最小值 imin

在合并线段树节点两边信息的时候我们用这样的一个式子:

\(lans[i]=max(max(lans[lc],lans[rc]),imax[lc]-imin[rc])\)

\(rans[i]=max(max(rans[lc],rans[rc]),imax[rc]-imin[lc])\)

\(imax[i]=max(imax[lc],imax[rc])\)

\(imin[i]=min(imin[lc],imin[rc])\)

然后更新就可以辣

现在就是树剖的时候 该怎么爬树

一般的树剖w是直接把深度大的交换之类的w但是现在涉及到一个方向问题w 所以我直接就比较了两个top

的深度然后直接暴力爬ww【雾】写的太丑了

然后由起点向上爬的时候就记录一个之前出现的最小值 lmin

然后用每次查出来的区间最大值去更新下 ans

这就表示在起点到LCA路径上的收益最大值

对于终点向上爬的时候同理维护一个之前出现的最大值 rmax

然后xjb跟之前一样搞一下 更新 ans

最后的时候再用 (rmax−lmin)

更新一下 ans

就可以了w

看代码吧w:


#include<bits/stdc++.h>
#define GO(i,here) for(int i=head[here];i!=-1;i=nex[i])
#define mem(i,j) memset(i,j,sizeof(i))
#define lc (i<<1)+1
#define rc (i<<1)+2
using namespace std;
const int MAXN=500001;
const int INF=1008610086;
int in(){
    int a(0),f(1);char c=getchar();
    while(c<'0'||c>'9') if(c=='-') f=-1,c=getchar();
    while(c>='0'&&c<='9') a=(a<<1)+(a<<3)+c-'0',c=getchar();
    return a*f;
}
int n,num[MAXN];
int dep[MAXN],fa[MAXN],siz[MAXN],son[MAXN],top[MAXN],rank[MAXN],r[MAXN],tot;
int head[MAXN],to[2*MAXN],nex[2*MAXN],top1;
struct Ans{
    int imax,imin,lans,rans;
};
struct Tree{
    int imax[2*MAXN+10],imin[2*MAXN+10];
    int lans[2*MAXN+10],rans[2*MAXN+10];//lans表示的是 左边大右边小 rans表示的是右边大左边小 
    int cha[2*MAXN+10];
    void build_tree(int l,int r,int i){
        if(l==r){
            lans[i]=rans[i]=0;imax[i]=imin[i]=num[rank[l]];
            return;
        }
        int mid=(l+r)>>1;
        build_tree(l,mid,lc);
        build_tree(mid+1,r,rc);
        lans[i]=max(max(lans[lc],lans[rc]),imax[lc]-imin[rc]);rans[i]=max(max(rans[lc],rans[rc]),imax[rc]-imin[lc]);
        imax[i]=max(imax[lc],imax[rc]);imin[i]=min(imin[lc],imin[rc]);
    }
    void pushdown(int i){
        if(!cha[i]) return;
        imax[lc]+=cha[i];imin[lc]+=cha[i];
        imax[rc]+=cha[i];imin[rc]+=cha[i];
        cha[lc]+=cha[i];cha[rc]+=cha[i];
        cha[i]=0;
    }
    void pushup(int i,int k){
        cha[i]+=k;
        imax[i]+=k;imin[i]+=k;
    }
    void update(int fl,int fr,int l,int r,int k,int i){
        if(fl<=l&&r<=fr){pushup(i,k);return;}
        if(fl>r||fr<l) return;
        pushdown(i);
        int mid=(l+r)>>1;
        update(fl,fr,l,mid,k,lc);update(fl,fr,mid+1,r,k,rc);
        lans[i]=max(max(lans[lc],lans[rc]),imax[lc]-imin[rc]);rans[i]=max(max(rans[lc],rans[rc]),imax[rc]-imin[lc]);
        imax[i]=max(imax[lc],imax[rc]);imin[i]=min(imin[lc],imin[rc]);
    }
    Ans query(int fl,int fr,int l,int r,int i){
        if(fl<=l&&r<=fr){
            Ans tmp;tmp.imax=imax[i];tmp.imin=imin[i];tmp.lans=lans[i];tmp.rans=rans[i];
            return tmp;
        }
        if(fl>r||fr<l){
            Ans tmp;tmp.imin=INF;tmp.imax=0;tmp.lans=0;tmp.rans=0;
            return tmp;
        }
        pushdown(i);
        int mid=(l+r)>>1;
        Ans ans,
            t1=query(fl,fr,l,mid,lc),
            t2=query(fl,fr,mid+1,r,rc);
        ans.imax=max(t1.imax,t2.imax);
        ans.imin=min(t1.imin,t2.imin);
        ans.lans=max(max(t1.lans,t2.lans),t1.imax-t2.imin);
        ans.rans=max(max(t1.rans,t2.rans),t2.imax-t1.imin);
        lans[i]=max(max(lans[lc],lans[rc]),imax[lc]-imin[rc]);rans[i]=max(max(rans[lc],rans[rc]),imax[rc]-imin[lc]);
        imax[i]=max(imax[lc],imax[rc]);imin[i]=min(imin[lc],imin[rc]);
        return ans;
    }
}tree;
void add(int a,int b){
    nex[top1]=head[a];head[a]=top1;to[top1++]=b;
    nex[top1]=head[b];head[b]=top1;to[top1++]=a;
}
void dfs1(int here,int d,int f){
    siz[here]=1;son[here]=-1;dep[here]=d;fa[here]=f;
    int qwq(0);
    GO(i,here){
        if(to[i]==f) continue;
        dfs1(to[i],d+1,here);
        siz[here]+=siz[to[i]];
        if(qwq<siz[to[i]]) qwq=siz[son[here]=to[i]];
    }
}
void dfs2(int here,int tp){
    rank[tot++]=here;top[here]=tp;r[here]=tot-1;
    if(son[here]==-1) return;
    dfs2(son[here],tp);
    GO(i,here){
        if(to[i]==son[here]||fa[here]==to[i]) continue;
        dfs2(to[i],to[i]);
    }
}
void input(){
    mem(head,-1);
    n=in();
    for(int i=1;i<=n;i++) num[i]=in();
    for(int i=1;i<n;i++){
        int a,b;
        a=in();b=in();
        add(a,b);
    }
    dfs1(1,0,0);
    dfs2(1,1);
    tree.build_tree(0,tot-1,0);
}
void xxj(){
    int m;
    m=in();
    for(int i=1;i<=m;++i){
        int a,b,v;
        a=in();b=in();
        v=in();int lmin(INF),rmax(0),ans(0);
        while(top[a]!=top[b]){
            if(dep[top[a]]>dep[top[b]]){//这个时候将a向上移动w 这个时候因为编号是递减的 所以说只需要看rans就可以了w然后用  
                Ans tmp=tree.query(r[top[a]],r[a],0,tot-1,0);
                tree.update(r[top[a]],r[a],0,tot-1,v,0);a=fa[top[a]];
                ans=max(ans,tmp.lans);ans=max(ans,tmp.imax-lmin);
                lmin=min(lmin,tmp.imin);
            }
            else{//这个时候b向上移动w 这个时候因为编号是递减的 所以说要lans
                Ans tmp=tree.query(r[top[b]],r[b],0,tot-1,0);
                tree.update(r[top[b]],r[b],0,tot-1,v,0);b=fa[top[b]];
                ans=max(ans,tmp.rans);ans=max(ans,rmax-tmp.imin);
                rmax=max(rmax,tmp.imax); 
            }
        }
        if(dep[a]>dep[b]){//a向上爬
            Ans tmp=tree.query(r[b],r[a],0,tot-1,0);
            tree.update(r[b],r[a],0,tot-1,v,0);
            ans=max(ans,tmp.lans);ans=max(ans,tmp.imax-lmin);
            lmin=min(lmin,tmp.imin);
        }
        else{//b向上爬 
            Ans tmp=tree.query(r[a],r[b],0,tot-1,0);
            tree.update(r[a],r[b],0,tot-1,v,0);
            ans=max(ans,tmp.rans);ans=max(ans,rmax-tmp.imin);
            rmax=max(rmax,tmp.imax);
        }
        ans=max(ans,rmax-lmin);
        printf("%d\n",ans);
    }
}

int main(){
    input();
    xxj();
    return 0;
}

转载于:https://www.cnblogs.com/Xiaojianxiang/p/6545502.html


http://www.niftyadmin.cn/n/1535960.html

相关文章

GDP含金量倒数第三与山东人的幸福

2009年GDP前三甲是广东、江苏、山东&#xff0c;分别为3.9万亿&#xff0c;3.4万亿&#xff0c;3.38万亿&#xff1b;2009年GDP含金量排名后三位是山东、新疆、内蒙古。前茅与垫底都有山东&#xff0c;或就是说&#xff0c;山东的GDP“含金量”与实际GDP的落差之大可以用惨不忍…

Mysql 唯一索引长度_关于mysql索引长度的相关内容总结

MySQL优化之-索引具体代码分析&#xff1a;索引是在存储引擎中实现的&#xff0c;因此每种存储引擎的索引都不一定完全相同&#xff0c;并且每种存储引擎也不一定支持所有索引类型。根据存储引擎定义每个表的最大索引数和最大索引长度。所有存储引擎支持每个表至少16个索引&…

Windows下安装Jekyll

一直以来使用jekyll更新文章时都是在Windows下的Linux虚拟机内构建&#xff0c;测试&#xff0c; 因为听闻Windows下安装比较麻烦&#xff0c;不过现在觉得打开虚拟机更麻烦&#xff0c; 所以本着不作死不罢休的精神开始了Windows下jekyll安装之旅... 安装Ruby和RubyDevKit 下载…

qt中文翻译步骤

第一步 在你的pro里面加入 TRANSLATIONS myexec_zh.ts 第二步 用lupdate 操作pro 将要翻译的提取到ts文件 命令是 lupdate my.pro 第三步 用 linguist 打开刚才的ts文件,linugist是在qt的bin的目录里面, 是一个界面工具 打开linguist 后用菜单栏file ->open 打开 相应的ts文…

java的socket包_Java的Unix Socket开发包 JUDS

授权协议: LGPL开发语言: Java操作系统: Linux软件介绍Java Unix Domain Sockets (JUDS) 提供了 Java 的方法用来访问 Unix domain sockets 套接字。示例代码&#xff1a;package com.google.code.juds.test;import java.io.IOException;import java.io.InputStream;import jav…

结对编程1 (201421123084,201421123062)

码市地址&#xff1a;https://coding.net/u/lzx84/p/Calculation/git 题目描述&#xff1a; 不知道大家是否尝试过这样一种开发模式&#xff1a;你有一个伙伴&#xff0c;你们坐在一起&#xff0c;并肩作战&#xff0c;面对着同一台显示器&#xff0c;使用着同一键盘&#xff0…

程序员能力矩阵 你属于哪一层?

注意:每个层次的知识都是渐增的&#xff0c;位于层次n&#xff0c;也蕴涵了你需了解所有低于层次n的知识。 计算机科学 Computer Science 软件工程 Software Engineering 程序设计 Programming 经验 Experience 【CSDN编者按】 上述图书中&#xff0c;第一级对应的英文为Unl…

C语言 · 字串逆序

算法训练 字串逆序 时间限制&#xff1a;1.0s 内存限制&#xff1a;512.0MB问题描述给定一个字符串&#xff0c;将这个串的所有字母逆序后输出。输入格式输入包含一个字符串&#xff0c;长度不超过100&#xff0c;字符串中不含空格。输出格式输出包含一个字符串&#xff0c;…