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. 几种.NET平台数据持久化框架介绍

    原文连接:http://yuxnet.blog.163.com/blog/static/164863495201131532223362/ 在.NET平台下,关于数据持久层框架非常多,本文主要对如下几 ...

  2. wcf的诡异问题

    最近在做工作流设计器用的silverlight 使用wcf服务. 过程中遇到了两个奇怪的问题. 1. 出现整型参数无法传递到服务器的情况 2.出现反序列化失败的情况. 经过仔细排查发现 每个属性都有一 ...

  3. React Native开发技术周报2

    (1).资讯 1.React Native 0.22_rc版本发布 添加了热自动重载功能 (2).技术文章 1.用 React Native 设计的第一个 iOS 应用 我们想为用户设计一款移动端的应 ...

  4. AsyncTask源码解析

    package com.example.demo.activity.net; import java.util.ArrayDeque; import java.util.concurrent.Bloc ...

  5. 【干货分享】JPager.Net MVC超好用轻量级分页控件

    JPager.Net  MVC好用的轻量级分页控件,好用到你无法想象,轻量到你无法想象. JPager.Net  MVC好用的轻量级分页控件,实现非常简单,使用也非常简单. JPager.Net  M ...

  6. 与Python Falling In Love_Python跨台阶(面向对象)

    第二课会介绍Python中的一些变量的使用.列表.元组.字典等一些详细内容...篇幅会比较多...因此在整理中... 先跳过第二课...直接来第三课..Python中面向对象的学习以及与mysql数据 ...

  7. APP架子迁移指南(二)

    接上一篇,这一篇开始用android来解释MVP概念.八股式的架子结构和命名规范.我在准备这篇文章的时候还看到不少在MVP基础上衍生的架子思路,底子是MVP没错,但命名有区别.复杂度变了.架子也用到了 ...

  8. 记、基于react-router的单页应用

    现在用react写单页应用基本上都是用react-router做前端路由了吧!最近在使用react-router的过程中遇到了不少问题,在这里总结一下. 浏览器url react-router默认提供 ...

  9. .Net分布式异常报警系统-客户端及服务端API

    客户端 客户端的作用就是捕获未处理异常, 发送异常到服务端. 关于捕获未处理异常的方法参考 http://www.cnblogs.com/youring2/archive/2012/04/25/246 ...

  10. android之拍照与摄像

    拍照和摄像的意图很简答,这里直接贴代码 布局文件 <?xml version="1.0" encoding="utf-8"?> <Linear ...