4127: Abs

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 381  Solved: 132
[Submit][Status][Discuss]

Description

给定一棵树,设计数据结构支持以下操作

1 u   v d  表示将路径 (u,v) 加d

2 u v 表示询问路径 (u,v) 上点权绝对值的和

Input

第一行两个整数n和m,表示结点个数和操作数

接下来一行n个整数a_i,表示点i的权值

接下来n-1行,每行两个整数u,v表示存在一条(u,v)的边

接下来m行,每行一个操作,输入格式见题目描述 

Output

对于每个询问输出答案

Sample Input

4 4
-4 1 5 -2
1 2
2 3
3 4
2 1 3
1 1 4 3
2 1 3
2 3 4

Sample Output

10
13
9

HINT

对于100%的数据,n,m <= 10^5 且 0<= d,|a_i|<= 10^8

Source

Solution

树链剖分显然,把树上路径问题转化为序列问题

然后线段树维护区间权值绝对值和,支持区间加

注意Delta>=0这个条件,即1操作保证加数不为负,即实际值不发生减小

于是线段树维护一些东西:

l,r左右端点;maxf区间最大负数;num区间正数个数-负数个数;tag区间加的标记;sum区间绝对值和

maxf的意义在于,对于区间加Delta,那么如果maxf+Delta<0很显然1操作后会出现变号的情况,对于维护绝对值和必然会做出影响,所以用来进行判断

num的意义在于计算sum的变化,这里同样可以考虑维护正数个数和负数个数,但Code起来比较不方便

tag的意义在于,如果区间+Delta不发生变号情况(即maxf+Delta<0||maxf>=0)的时候,可以直接打上标记,否则则需要把标记下放至叶节点,在向上更新答案

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define maxn 110000
int n,m,a[maxn];
struct Edgenode{int to,next;}edge[maxn<<];
int head[maxn],cnt=;
void add(int u,int v){cnt++; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt;}
void insert(int u,int v){add(u,v); add(v,u);}
//----------------------------------------------------------------------------------
int size[maxn],fa[maxn],deep[maxn],son[maxn],pl[maxn],sz,pre[maxn],top[maxn],pr[maxn];
void dfs_1(int now)
{
size[now]=;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=fa[now])
{
fa[edge[i].to]=now;
deep[edge[i].to]=deep[now]+;
dfs_1(edge[i].to);
if (size[son[now]]<size[edge[i].to]) son[now]=edge[i].to;
size[now]+=size[edge[i].to];
}
}
void dfs_2(int now,int chain)
{
pl[now]=++sz; pre[sz]=a[now]; top[now]=chain;
if (son[now]) dfs_2(son[now],chain);
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=son[now] && edge[i].to!=fa[now])
dfs_2(edge[i].to,edge[i].to);
pr[now]=sz;
}
//----------------------------------------------------------------------------------
struct TreeNode
{
int l,r;long long maxf,tag,sum,num;
void Add(int k)
{
if (k<) maxf=k,sum=-k,num=-;
else maxf=,sum=k,num=;
tag=;
}
}tree[maxn<<];
long long Maxf(long long x,long long y)
{
if (x>= && y>=) return ;
if (x>= || y>=) return min(x,y);
return max(x,y);
}
void Update(int now)
{
tree[now].maxf=Maxf(tree[now<<].maxf,tree[now<<|].maxf);
tree[now].sum=tree[now<<].sum+tree[now<<|].sum;
tree[now].num=tree[now<<].num+tree[now<<|].num;
}
void BuildTree(int now,int l,int r)
{
tree[now].l=l,tree[now].r=r;
if (l==r) {tree[now].Add(pre[l]); return;}
int mid=(l+r)>>;
BuildTree(now<<,l,mid); BuildTree(now<<|,mid+,r);
Update(now);
}
void Pushdown(int now)
{
if (!tree[now].tag || tree[now].l==tree[now].r) return;
int tag=tree[now].tag; tree[now].tag=;
tree[now<<].maxf+=tag; tree[now<<].sum+=tree[now<<].num*tag; tree[now<<].tag+=tag;
tree[now<<|].maxf+=tag; tree[now<<|].sum+=tree[now<<|].num*tag; tree[now<<|].tag+=tag;
}
void Change(int now,int L,int R,int D)
{
int l=tree[now].l,r=tree[now].r;
if (L<=l && R>=r && (tree[now].maxf>= || tree[now].maxf+D<))
{tree[now].maxf+=D; tree[now].sum+=(long long)tree[now].num*D; tree[now].tag+=D; return;}
if (l==r) {tree[now].Add(tree[now].maxf+D); return;}
Pushdown(now);
int mid=(l+r)>>;
if (L<=mid) Change(now<<,L,R,D);
if (R>mid) Change(now<<|,L,R,D);
Update(now);
}
long long Query(int now,int L,int R)
{
Pushdown(now);
int l=tree[now].l,r=tree[now].r;
if (L<=l && R>=r) return tree[now].sum;
int mid=(l+r)>>; long long re=;
if (L<=mid) re+=Query(now<<,L,R);
if (R>mid) re+=Query(now<<|,L,R);
return re;
}
void DeBug(int now)
{
int l=tree[now].l,r=tree[now].r;
if (l==r) {printf("l==r=%d Val=%d maxf=%lld tag=%lld sum=%lld num=%lld\n",l,a[l],tree[now].maxf,tree[now].tag,tree[now].sum,tree[now].num);return;}
int mid=(l+r)>>;
DeBug(now<<); DeBug(now<<|);
}
//----------------------------------------------------------------------------------
void Solve_1(int x,int y,int D)
{
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
Change(,pl[top[x]],pl[x],D);
x=fa[top[x]];
}
if (deep[x]>deep[y]) swap(x,y);
Change(,pl[x],pl[y],D);
}
long long Solve_2(int x,int y)
{
long long re=;
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
re+=Query(,pl[top[x]],pl[x]);
x=fa[top[x]];
}
if (deep[x]>deep[y]) swap(x,y);
re+=Query(,pl[x],pl[y]);
return re;
}
//----------------------------------------------------------------------------------
int main()
{
// freopen("4127.in","r",stdin);
// freopen("4127.out","w",stdout);
n=read(),m=read();
for (int i=; i<=n; i++) a[i]=read();
for (int u,v,i=; i<=n-; i++) u=read(),v=read(),insert(u,v);
dfs_1(); dfs_2(,); BuildTree(,,n);
int opt,u,v,w;
while (m--)
{
opt=read();
// DeBug(1);
if (opt==) u=read(),v=read(),w=read(),Solve_1(u,v,w);
else u=read(),v=read(),printf("%lld\n",Solve_2(u,v));
}
return ;
}

友情附送数据生成器:(Designed by YveH)

#include<ctime>
#include<cstdio>
#include<cstdlib>
using namespace std;
int main()
{
freopen("4127.in","w",stdout);
srand(time());
int n=,q=;
printf("%d %d\n",n,q);
for (int i=;i<=n;i++)
printf("%d ",rand()%-);
printf("\n");
for (int i=;i<=n;i++)
printf("%d %d\n",i,rand()%(i-)+);
for (int i=;i<=q;i++)
{
int opt=rand()%+;
printf("%d ",opt);
if (opt==)
printf("%d %d %d\n",rand()%n+,rand()%n+,rand()%);
if (opt==)
printf("%d %d\n",rand()%n+,rand()%n+);
}
return ;
}

数据生成器

友情附送对拍:(Designed by YveH)

#include<iostream>
#include<cstdio>
#include<windows.h>
using namespace std;
int main()
{
while ()
{
system("4127data.exe");
system("4127.exe");
system("4127STD.exe");
if (system("fc 4127.out 4127std.out"))
break;
}
return ;
}

对拍

这道破题,两天前YveH和Etienne写了半天多,DCrusher大爷嘲讽他们,我替他们不服,然后自己果断写了1小时,然后调了3小时....发现自信写不错的链剖少打了一句话MDZZ

(加上省队集训,第三题暴力打到70%就去吃饭了,回来懒得打了,体验了连续滚粗的快感)

发现自己的常数已经接近Etienne了...就慢个100ms不到

【BZOJ-4127】Abs 树链剖分 + 线段树 (有趣的姿势)的更多相关文章

  1. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  2. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  3. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  4. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  5. 【bzoj4127】Abs 树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  6. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

  7. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  8. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  9. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  10. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

随机推荐

  1. 转载和积累系列 - 深入理解HTTP协议

    深入理解HTTP协议 1. 基础概念篇 1.1 介绍 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写.它的发展是万维网协会(World Wide Web C ...

  2. Windows7 64位压缩包安装MySQL5.7.9

    官网下载64bit MySQL5.7.9压缩包, 解压至安装位置 1. 创建my.ini文件, 内容如下 [mysqld] # Remove leading # and set to the amou ...

  3. 01Spring_基本jia包的导入andSpring的整体架构and怎么加入日志功能

    1.什么是Spring : v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:u ...

  4. Swagger 增加 DocumentFilter 隐藏不需要显示的接口

    services.ConfigureSwaggerGen(options => { options.SingleApiVersion(new Info { Version = "v1& ...

  5. HP PCS 云监控大数据解决方案

    ——把数据从分散统一集中到数据中心 基于HP分布式并行计算/存储技术构建的云监控系统即是通过“云高清摄像机”及IaaS和PaaS监控系统平台,根据用户所需(SaaS)将多路监控数据流传送给“云端”,除 ...

  6. C# 6.0

    C# 6.0 的新语法特性   回眸 C# 的前世今生 - 见证 C# 6.0 的新语法特性 序 目前最新的版本是 C# 7.0,VS 的最新版本为 Visual Studio 2017 RC,两者都 ...

  7. Oracle Coherence应用部署到Jboss EAP 6.x 时 NoClassDefFoundError: sun/rmi/server/MarshalOutputStream 的解决办法

    今天将一个web应用从weblogic 10.3迁移到jboss EAP 6.3上,该应用使用oracle coherence做为缓存,部署上去后,启动时一直报如下错误:     at java.ut ...

  8. 利用Canvas进行绘制XY坐标系

    首先来一发图 绘制XY的坐标主要是利用Canvas setLeft和setBottom功能(Canvas内置坐标的功能) 1.首先WPF中的坐标系都是从左到右,从上到下的 即左上角位置(0,0)点,所 ...

  9. MATLAB中白噪声的WGN和AWGN函数的使用

    MATLAB中白噪声的WGN和AWGN函数的使用如下: MATLAB中产生高斯白噪声非常方便,可以直接应用两个函数,一个是WGN,另一个是AWGN.WGN用于产生高斯白噪声,AWGN则用于在某一 信号 ...

  10. android之Activity回传数据

    约定:当Activity发生跳转时将原来的Activity成为父Activity,将新出现的Activity成为子Activity. 情景设置 下面是个发短信的Activity 当我们点击图中的+按钮 ...