您的位置:首页 > 其它

BZOJ[4127] Abs

2015-06-21 20:12 288 查看
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=4127

不算难的样子,才见过此类模型。

首先可以发现每次修改只增不减,那么这$O(n)$的负数最多只会有$n$次由负变正。

所以对于每一次由负变正我们暴力在线段树上维护,每一次由负变正在线段树上会经过$O(logn)$层。

效率$O(logn)$。

其他的维护一下区间负数的个数什么的就可以搞了。

一遍AC爽

#include <cstdio>
#include <cstring>
#include <algorithm>

#define l(x) ch[x][0]
#define r(x) ch[x][1]
#define N 100010
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3fLL

using namespace std;

struct edge{
int x,to;
}E[N<<1];

int n,m,totE;
int g
;

inline int Abs(int x){
if(x<0) return -x;
return x;
}

inline void ade(int x,int y){
E[++totE]=(edge){y,g[x]}; g[x]=totE;
}

namespace Segtree{
int tot;
int ch[N<<1][2];
int totf[N<<1],siz[N<<1];
LL maxf[N<<1],sumv[N<<1],addv[N<<1];

void push(int x){
if(!l(x)||!addv[x]) return;
addv[l(x)]+=addv[x];
sumv[l(x)]+=addv[x]*(LL)(siz[l(x)]-2*totf[l(x)]);
maxf[l(x)]+=addv[x];
addv[r(x)]+=addv[x];
sumv[r(x)]+=addv[x]*(LL)(siz[r(x)]-2*totf[r(x)]);
maxf[r(x)]+=addv[x];
addv[x]=0;
}

void up(int x){
if(!l(x)) return;
sumv[x]=sumv[l(x)]+sumv[r(x)];
maxf[x]=max(maxf[l(x)],maxf[r(x)]);
totf[x]=totf[l(x)]+totf[r(x)];
}

void change(int x,int l,int r,int ql,int qr,int qv){
push(x);
if(ql<=l&&r<=qr&&maxf[x]+qv<0){
addv[x]+=qv;
sumv[x]+=qv*(LL)(siz[x]-2*totf[x]);
maxf[x]+=qv;
}
else if(l==r){
sumv[x]=qv-sumv[x];
addv[x]=0;
maxf[x]=-INF;
totf[x]=0;
}
else{
int mid=(l+r)>>1;
if(ql<=mid) change(l(x),l,mid,ql,qr,qv);
if(mid<qr)  change(r(x),mid+1,r,ql,qr,qv);
up(x);
}
}

LL ask(int x,int l,int r,int ql,int qr){
push(x);
if(ql<=l&&r<=qr){
return sumv[x];
}
int mid=(l+r)>>1;
LL ans=0;
if(ql<=mid) ans+=ask(l(x),l,mid,ql,qr);
if(mid<qr)  ans+=ask(r(x),mid+1,r,ql,qr);
up(x);
return ans;
}

int build(int src[],int l,int r){
int x=++tot;
siz[x]=r-l+1;
if(l==r){
sumv[x]=Abs(src[l]);
addv[x]=0;
if(src[l]>=0) maxf[x]= -INF;
else maxf[x]=src[l];
totf[x]= (src[l]<0) ? 1:0;
return x;
}
int mid=(l+r)>>1;
l(x)=build(src,l,mid);
r(x)=build(src,mid+1,r);
up(x);
return x;
}
}

#define p E[i].x

int tott;
int L
,a
,fa
,pos
,c
,d
,siz
,h
,top
;
bool v
;

void dfs(int x){
v[x]=1; siz[x]=1; h[x]=0;
for(int i=g[x];i;i=E[i].to)
if(!v[p]){
fa[p]=x;
d[p]=d[x]+1;
dfs(p);
siz[x]+=siz[p];
if(siz[p]>siz[h[x]])
h[x]=p;
}
}

void cut(int x,int ft){
L[x]=++tott; c[tott]=a[x]; pos[tott]=x; top[x]=ft;
if(h[x]) cut(h[x],ft);
for(int i=g[x];i;i=E[i].to)
if(p!=fa[x]&&p!=h[x])
cut(p,p);
}

void change(int x,int y,int v){
int f1=top[x],f2=top[y];
while(f1!=f2){
if(d[f1]<d[f2]) swap(f1,f2),swap(x,y);
Segtree::change(1,1,n,L[f1],L[x],v);
x=fa[f1]; f1=top[x];
}
if(L[x]>L[y]) swap(x,y);
Segtree::change(1,1,n,L[x],L[y],v);
}

LL ask(int x,int y){
int f1=top[x],f2=top[y];
LL ans=0;
while(f1!=f2){
if(d[f1]<d[f2]) swap(f1,f2),swap(x,y);
ans+=Segtree::ask(1,1,n,L[f1],L[x]);
x=fa[f1]; f1=top[x];
}
if(L[x]>L[y]) swap(x,y);
ans+=Segtree::ask(1,1,n,L[x],L[y]);
return ans;
}

int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int cmd,x,y;
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
ade(x,y); ade(y,x);
}
d[1]=1;
dfs(1); cut(1,1);
Segtree::build(c,1,n);
for(int i=1;i<=m;i++){
int v;
scanf("%d%d%d",&cmd,&x,&y);
if(cmd==1){
scanf("%d",&v);
change(x,y,v);
}
else printf("%lld\n",ask(x,y));
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: