BZOJ4127 : Abs

树链剖分+线段树。

线段树每个区间[l,r]维护:

m:最大的负数

s:所有数字绝对值的和

d:正数的个数-负数的个数

t:懒惰标记

区间修改时,若最大的负数<0且最大的负数+p>=0,则暴力递归,否则打标记。

因为每个负数只会被暴力修改一次,所以时间复杂度为$O(n\log^2n)$。

#include<cstdio>
#define N 100010
typedef long long ll;
int n,m,i,op,x,y,z,a[N];ll ans;
int g[N],v[N<<1],nxt[N<<1],ed,size[N],son[N],f[N],d[N],top[N],loc[N],dfn,seq[N];
struct P{
  ll m,s,t;int d;
  P(){}
  inline void set(int x){
    t=0;
    if(x<0)m=x,s=-x,d=-1;else m=0,s=x,d=1;
  }
}T[262145];
inline int merge(int a,int b){
  if(a>=0&&b>=0)return 0;
  if(a>=0)return b;
  if(b>=0)return a;
  return a>b?a:b;
}
inline void add1(int x,ll p){
  T[x].m+=p;
  T[x].s+=p*T[x].d;
  T[x].t+=p;
}
inline void pb(int x){if(T[x].t)add1(x<<1,T[x].t),add1(x<<1|1,T[x].t),T[x].t=0;}
inline void up(int x){
  T[x].m=merge(T[x<<1].m,T[x<<1|1].m);
  T[x].s=T[x<<1].s+T[x<<1|1].s;
  T[x].d=T[x<<1].d+T[x<<1|1].d;
}
void build(int x,int a,int b){
  if(a==b){T[x].set(seq[a]);return;}
  int mid=(a+b)>>1;
  build(x<<1,a,mid),build(x<<1|1,mid+1,b),up(x);
}
void change(int x,int a,int b,int c,int d,int p){
  if(c<=a&&b<=d&&(T[x].m>=0||T[x].m+p<0)){add1(x,p);return;}
  if(a==b){T[x].set(T[x].m+p);return;}
  pb(x);
  int mid=(a+b)>>1;
  if(c<=mid)change(x<<1,a,mid,c,d,p);
  if(d>mid)change(x<<1|1,mid+1,b,c,d,p);
  up(x);
}
void ask(int x,int a,int b,int c,int d){
  if(c<=a&&b<=d){ans+=T[x].s;return;}
  pb(x);
  int mid=(a+b)>>1;
  if(c<=mid)ask(x<<1,a,mid,c,d);
  if(d>mid)ask(x<<1|1,mid+1,b,c,d);
  up(x);
}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x,int y){
  size[x]=1,d[x]=d[f[x]=y]+1;
  for(int i=g[x];i;i=nxt[i])if(v[i]!=y){
    dfs(v[i],x);size[x]+=size[v[i]];
    if(size[v[i]]>size[son[x]])son[x]=v[i];
  }
}
void dfs2(int x,int y){
  top[x]=y;seq[loc[x]=++dfn]=a[x];
  if(son[x])dfs2(son[x],y);
  for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
}
inline void modify(int x,int y,int p){
  for(;top[x]!=top[y];x=f[top[x]]){
    if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
    change(1,1,n,loc[top[x]],loc[x],p);
  }
  if(d[x]<d[y]){int z=x;x=y;y=z;}
  change(1,1,n,loc[y],loc[x],p);
}
inline void query(int x,int y){
  for(ans=0;top[x]!=top[y];x=f[top[x]]){
    if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
    ask(1,1,n,loc[top[x]],loc[x]);
  }
  if(d[x]<d[y]){int z=x;x=y;y=z;}
  ask(1,1,n,loc[y],loc[x]);
  printf("%lld\n",ans);
}
inline void read(int&a){char c;while(!(((c=getchar())>=‘0‘)&&(c<=‘9‘)));a=c-‘0‘;while(((c=getchar())>=‘0‘)&&(c<=‘9‘))(a*=10)+=c-‘0‘;}
inline void read2(int&a){
  char c;bool f=0;a=0;
  while(!((((c=getchar())>=‘0‘)&&(c<=‘9‘))||(c==‘-‘)));
  if(c!=‘-‘)a=c-‘0‘;else f=1;
  while(((c=getchar())>=‘0‘)&&(c<=‘9‘))(a*=10)+=c-‘0‘;
  if(f)a=-a;
}
int main(){
  read(n),read(m);
  for(i=1;i<=n;i++)read2(a[i]);
  for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
  dfs(1,0),dfs2(1,1),build(1,1,n);
  while(m--){
    read(op),read(x),read(y);
    if(op==1)read(z),modify(x,y,z);else query(x,y);
  }
  return 0;
}

  

时间: 2024-08-27 07:49:57

BZOJ4127 : Abs的相关文章

【BZOJ4127】Abs 树链剖分+线段树

[BZOJ4127]Abs 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

【BZOJ-4127】Abs 树链剖分 + 线段树 (有趣的姿势)

4127: Abs Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 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

模板:abs用法

c语言书本上说,数学函数除了求整数的绝对值函数abs()之外<abs() 定义在stdlib.h中>,其余的函数都在头文件 math.h 中定义,包括对浮点数求绝对值的函数fabs().c++中,包含的相应的头文件为,原则是前面加c,同时去掉.h .例如:#include <cstdlib>对应        #include <stdlib.h>#include <cmath>对应        #include <math.h> 于是,在c+

ZOJ 3789 Abs Problem

有时候像这种题,没有明显的思路,感觉像规律题.那么先暴力打表,再找规律就很快了. 题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3798 先上我的暴力打表,这种肯定是TLE的,只用它发现规律就好了. #include<cstdio> #include<cstring> #include<algorithm> #define INF 0x3f3f3f3f #define N 100 us

abs函数

原型: double abs (double x); float abs (float x); long double abs (long double x); double abs (T x); // additional overloads for integral types代码: // cmath's abs example #include <iostream> // std::cout #include <cmath> // std::abs int main () {

ABS(x)

ABS(x) 用于返回 x 的绝对值 mysql> SELECT ABS(2), ABS(-2.3), ABS(-33); +--------+-----------+----------+ | ABS(2) | ABS(-2.3) | ABS(-33) | +--------+-----------+----------+ | 2 | 2.3 | 33 | +--------+-----------+----------+

那个你经常用的abs函数(取绝对值)真的总是返回非负数吗?

前几天在牛客网看到一道关于abs()函数返回值的题目,见下图,当时还没反应过来,第一反应是:自从我开始学C语言,就知道它是用来求int数的绝对值的,返回值当然是0或者正数啊,一看答案就是A. 后来思来想去,质问自己 难道这道题就这么简单?于是果断先查函数库,得到: #include <stdlib.h> //或math.h int abs( int num ); 发现库函数的返回值形式都写的是int,为什么是int?经过深入的思考.验证和查阅资料,最后得出: 当num为0或正数时,函数返回nu

什么是MBS,ABS和CDO

1. 都是资产证券化产品 华尔街有句名言“如果要增加未来的现金流,就把它做成证券.如果想经营风险,就把它做成证券”.从本质上来讲,MBS,ABS和 CDO都是资产证券化产品.根据美国证券交易委员会(SEC)给出的定义,资产证券化,指产生这样一种证券,它们主要是由一个特定的应收款资产池或其他金融资产池来支持(backed),保证偿付.而这些资产证券化产品的价值P可以用下面公式来表示:其中,n为资产池中应收账款或其他金融资产的偿还年限.不难看出,资产证券化产品的价值P受未来现金流量及市场利率r的影响

Python的内置方法,abs,all,any,basestring,bin,bool,bytearray,callable,chr,cmp,complex,divmod

Python的内置方法 abs(X):返回一个数的绝对值,X可以是一个整数,长整型,或者浮点数,如果X是一个复数,此方法返回此复数的绝对值(此复数与它的共轭复数的乘积的平方根) >>> abs(3+2j) 3.605551275463989 >>> abs(3-2j) 3.605551275463989 all(iterable):如果迭代器的所有元素都是true,或者空迭代器,则此方法返回true. any(iterable):迭代器只要有一个元素为false,或者空