题目传送门

题目大意: 求树上最大子段和,带修。

如果做了gss系列的前六题,那么这题相信不难。用一个树链剖分维护这棵树即可。

但是细节比较烦。

具体做法:对于求 x x x到 y y y路径上的最大子段和,只需要让 x x x和 y y y往上跑一遍,将经过的链的信息合并在一起即可,但是最后当 x x x和 y y y在一条重链上时,我们需要将 x x x经过的链的信息和 y y y经过的链的信息合并,而此时这两个信息的左端点都朝上,于是可以将其中一个翻转,于是就可以接起来了。

具体细节看代码,会有很清楚的注释 (毕竟自己都觉得上面这个讲的不明白):

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 100010struct edge{int y,next;};
edge e[maxn*2];
int first[maxn];
int n,m,a[maxn];
void buildroad(int x,int y)
{static int len=0;e[++len]=(edge){y,first[x]};first[x]=len;
}
int fa[maxn],size[maxn],mson[maxn],deep[maxn];
void dfs1(int x)//树剖预处理,找到重儿子,求出深度之类的
{size[x]=1;for(int i=first[x];i;i=e[i].next){int y=e[i].y;if(y==fa[x])continue;fa[y]=x;deep[y]=deep[x]+1;dfs1(y);if(size[y]>size[mson[x]])mson[x]=y;size[x]+=size[y];}
}
int now[maxn],old[maxn],top[maxn],tot=0;
void dfs2(int x,int tt)//树剖预处理,给每个点重新编号
{now[x]=++tot;old[tot]=x;top[x]=tt;if(mson[x]!=0)dfs2(mson[x],tt);for(int i=first[x];i;i=e[i].next)if(e[i].y!=fa[x]&&e[i].y!=mson[x])dfs2(e[i].y,e[i].y);
}
struct node{int l,r,sl,sr,ans,sum,lazy;node *zuo,*you;void check(node *le,node *ri)//表示将两个点的信息合并到自己身上{if(le==NULL||ri==NULL)//如果只有一个点,就直接继承{if(le==NULL)sum=ri->sum,sl=ri->sl,sr=ri->sr,ans=ri->ans;else sum=le->sum,sl=le->sl,sr=le->sr,ans=le->ans;return;}sum=le->sum+ri->sum;sl=max(le->sl,le->sum+ri->sl);sr=max(ri->sr,ri->sum+le->sr);ans=max(le->ans,max(ri->ans,le->sr+ri->sl));}node(int x,int y)//建树{if(x==0)return;l=x,r=y;lazy=-23333;//注意lazy不能为0,因为修改操作是可以为0的,在没有修改操作时lazy的绝对值要大于10000保证不和修改操作冲突if(l<r){int mid=l+r>>1;zuo=new node(x,mid);you=new node(mid+1,y);check(zuo,you);}else sum=sl=sr=ans=a[old[x]],zuo=NULL,you=NULL;}node *get(int x,int y)//求x~y的最大子段和{pushdown();if(l==x&&r==y)//如果完全符合,注意不能直接返回自己,要新建一个点继承自己的信息然后返回这个点{//因为在ask函数中会有将点的信息翻转的操作,如果直接返回自己可能会把自己的信息搞乱//顺便扯一句,就是因为这个WA了半天node *re=new node(0,0);//注意不是re=this,不然的话跟返回this没有区别re->check(this,NULL);//继承信息return re;}int mid=l+r>>1;if(y<=mid)return zuo->get(x,y);else if(x>=mid+1)return you->get(x,y);else{node *left=zuo->get(x,mid),*right=you->get(mid+1,y);node *re=new node(0,0);re->check(left,right);return re;}}void pushdown(){if(lazy!=-23333){if(lazy>0)sl=sr=sum=ans=(r-l+1)*lazy;else sl=sr=ans=lazy,sum=(r-l+1)*lazy;if(zuo!=NULL)zuo->lazy=lazy,you->lazy=lazy;lazy=-23333;}}void change(int x,int y,int z)//将x~y的值改成z{if(l==x&&r==y){lazy=z;pushdown();return;}pushdown();int mid=l+r>>1;if(y<=mid)zuo->change(x,y,z),you->pushdown();else if(x>=mid+1)you->change(x,y,z),zuo->pushdown();else zuo->change(x,mid,z),you->change(mid+1,y,z);check(zuo,you);}
};
node *root;
void ask(int x,int y)//重头戏在此
{node *l=NULL,*r=NULL;//*l,*r用来存x和y往上跑时一路上的信息bool v=false;//v记录x和y时交换过的还是没交换过的,结合代码感性理解(虽然不知道有没有用)while(top[x]!=top[y]){if(deep[top[x]]>deep[top[y]])swap(x,y),swap(l,r),v^=1;//注意这里l和r也要交换node *wula=root->get(now[top[y]],now[y]);//记录下当前点到重链顶端的答案if(r==NULL)r=wula;//如果之前没有信息,就直接存else{node *wulala=new node(0,0);wulala->check(wula,r);//否则将以前的信息和现在的信息合并,注意,这里面一定是(wula,r),而不能是(r,wula)r=wulala;}y=fa[top[y]];}if(deep[x]>deep[y])swap(x,y),swap(l,r),v^=1;node *wula=root->get(now[x],now[y]);//当x和y在同一条链上时,最后求出x到y的最大子段和if(v)swap(l,r),swap(wula->sl,wula->sr);//最后要让l的右端点对着wula的左端点,wula的右端点对着r的左端点//这样才能正常的合并if(l!=NULL)swap(l->sl,l->sr);//注意记得判l是否为NULLnode *wulala=new node(0,0);//最后将三者的信息合并wulala->check(l,wula);wula->check(wulala,r);if(wula->ans>=0)printf("%d\n",wula->ans);//如果小于0,不如不选else printf("0\n");
}
void change(int x,int y,int z)
{while(top[x]!=top[y])//这个很简单,跑一遍沿路修改即可{if(deep[top[x]]>deep[top[y]])swap(x,y);root->change(now[top[y]],now[y],z);y=fa[top[y]];}if(deep[x]>deep[y])swap(x,y);root->change(now[x],now[y],z);
}int main()
{scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<n;i++){int x,y;scanf("%d %d",&x,&y);buildroad(x,y);buildroad(y,x);}dfs1(1);dfs2(1,1);root=new node(1,n);scanf("%d",&m);for(int i=1;i<=m;i++){int id,x,y,z;scanf("%d",&id);switch(id){case 1:scanf("%d %d",&x,&y);ask(x,y);break;case 2:scanf("%d %d %d",&x,&y,&z);change(x,y,z);break;}}
}

GSS7 - Can you answer these queries VII 题解相关推荐

  1. HDU 1027 G - Can you answer these queries?

    http://acm.hdu.edu.cn/showproblem.php?pid=4027 Can you answer these queries? Time Limit: 4000/2000 M ...

  2. SPOJ GSS3-Can you answer these queries III-分治+线段树区间合并

    Can you answer these queries III SPOJ - GSS3 这道题和洛谷的小白逛公园一样的题目. 传送门: 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间 ...

  3. 线性代数四之动态DP(广义矩阵加速)——Can you answer these queries III,保卫王国

    动态DP--广义矩阵加速 SP1716 GSS3 - Can you answer these queries III description solution code [NOIP2018 提高组] ...

  4. SPOJ GSS2 Can you answer these queries II (线段树离线) - xgtao -

    Can you answer these queries II 这是一道线段树的题目,维护历史版本,给出N(<=100000)个数字(-100000<=x<=100000),要求求出 ...

  5. HDU 4027 Can you answer these queries?(线段树/区间不等更新)

    传送门 Can you answer these queries? Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/6576 ...

  6. GSS2 - Can you answer these queries II

    GSS2 - Can you answer these queries II 题意: 给你1e51e51e5 的序列,每次询问区间l到rl到rl到r,每个相同的数只算一次的最大子段和. 思路: 乍一眼 ...

  7. 题解 SP2916 【GSS5 - Can you answer these queries V】

    前言 最近沉迷于数据结构,感觉数据结构很有意思. 正文 分析 先来分类讨论一下 1. x2<y1x2<y1x2<y1 如果 y1<x2y1<x2y1<x2 的话,答 ...

  8. Can you answer these queries III (线段树维护最大子段和)

    题意: 求一个区间的最大连续和. 0:表示把A[x]改成y 1:表示求[x,y]这个区间的最大连续和. 题解: 线段树维护四个变量. 倒着讲,先来看如何维护这四个变量. summax代表这个区间连续最 ...

  9. hdu - 4027 Can you answer these queries?

    http://acm.hdu.edu.cn/showproblem.php?pid=4027 /** * 题意:给你n个数,对这些数进行操作,有m组操作 * q == 0 [x,y]区间内的每个数开方 ...

最新文章

  1. TCP/IP原理 (一)
  2. oracle数据表管理
  3. 如何使用SAP Fiori Launchpad Designer
  4. Scanner进阶详细讲解
  5. 面试官:大型系统架构设计细节你知道多少??
  6. 如何制作毛玻璃效果?
  7. 利用windows 2003实现服务器群集的搭建与架设(二)
  8. 【Python-2.7】切片
  9. Neo4j数据导入与可视化
  10. 集群为什么最少6个_结构化面试答题技巧:多年的经验告诉你,最少要注意这6个方面...
  11. Annie——一个简洁强大的轻量级视频下载神器
  12. Linux命令学习符以及安装程序
  13. 怎么把外部参照合并到图纸_如何在CAD制图中将两个图合并到一个图纸上
  14. oracle全备份脚本,Oracle全库备份脚本
  15. 韩信点兵问题的神解法
  16. Swift3.0知识点:高度模仿斗鱼TV(一)
  17. cxf调用报错Could not find conduit initiator for address:
  18. h264编码流程分析
  19. iframe 去除边框和自适应高度
  20. Python spider (二) Requests Lxml bs4

热门文章

  1. 【3B1B笔记】e的矩阵指数——怎么算?为什么?
  2. 防护等级IP代码的意义
  3. 导出excel,前后台代码示例
  4. 简体字与繁体字对照表 “学习繁体字”
  5. windows下TortoiseGit安装教程
  6. 商务智能-第五章 多维建模
  7. 【SEO】一个推广竞价员的自我修养
  8. 码code | 利用AI技术,你的小程序也能图文识别
  9. iOS黑(灰)白化实现方案
  10. 日本禅师铃木俊隆的12条生活准则