bzoj 4127: Abs 树链剖分
4127: Abs
Time Limit: 40 Sec Memory Limit: 256 MB
Submit: 11 Solved: 5
[Submit][Status][Discuss]
Description
给定一棵树,设计数据结构支持以下操作
1 u v d 表示将路径 (u,v) 加d
2 u v 表示询问路径 (u,v) 上点权绝对值的和
Input
接下来一行n个整数a_i,表示点i的权值 接下来n-1行,每行两个整数u,v表示存在一条(u,v)的边 接下来m行,每行一个操作,输入格式见题目描述
Output
Sample Input
-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
13
9
HINT
对于100%的数据,n,m <= 10^5 且 0<= d,|a_i|<= 10^8
我们分开处理正数负数情况,注意加数为正,所以一个负数被加成正数最多发生O(n)次,我们需要实现的就是快速的判定是否有某个负数加成了正数,维护负数集合中的最大值和位置即可。如果负数集合的最大值大于0,那么我们求得最大值所在位置,然后暴力将它修改到正数集合即可。
注意这道题INF取0x3f3f3f3f要出事。
第一次写链剖的每个链单独建线段树版本,不是太难。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 210000
#define MAXT MAXN*4
#define MAXV MAXN
#define MAXE MAXN*2
#define INFL 0x3f3f3f3f3f3f3f3f
#define smid ((l+r)>>1)
#define abs(x) ((x)>0?x:-(x))
typedef long long qword;
inline int nextInt()
{
register char ch;
register int x=;
register bool f=false;
while (ch=getchar(),ch<'' || ch>'')f|=ch=='-';
while (x=x*+ch-'',ch=getchar(),ch<='' && ch>='');
return x*(f?-:);
}
struct sgt_node
{
int lc,rc;
int sd;
qword sv;
qword pls;
pair<qword,int> mx;
}sgt[MAXT];
int topt=;
int a[MAXN];
int b[MAXN];
void update(int now)
{
sgt[now].mx=max(sgt[sgt[now].lc].mx,sgt[sgt[now].rc].mx);
sgt[now].sd=sgt[sgt[now].lc].sd+sgt[sgt[now].rc].sd;
sgt[now].sv=sgt[sgt[now].lc].sv+sgt[sgt[now].rc].sv;
}
void make_plus(int now,int l,int r,qword delta)
{
sgt[now].sv+=(qword)sgt[now].sd*delta;
sgt[now].pls+=delta;
sgt[now].mx.first+=delta;
}
void down(int now,int l,int r)
{
if (sgt[now].pls)
{
make_plus(sgt[now].lc,l,smid,sgt[now].pls);
make_plus(sgt[now].rc,smid+,r,sgt[now].pls);
sgt[now].pls=;
}
}
void Build_sgt(int &now,int l,int r)
{
now=++topt;
if (l==r)
{
sgt[now].sd=b[l]<?-:;
sgt[now].sv=abs(b[l]);
if (b[l]<)
{
sgt[now].mx=make_pair(b[l],l);
}else
{
sgt[now].mx=make_pair(-INFL,-);
}
return ;
}
Build_sgt(sgt[now].lc,l,smid);
Build_sgt(sgt[now].rc,smid+,r);
update(now);
}
void Add_sgt(int now,int l,int r,int x,int y,int delta)
{
if (l==x && r==y)
{
make_plus(now,l,r,delta);
return ;
}
down(now,l,r);
if (y<=smid)
Add_sgt(sgt[now].lc,l,smid,x,y,delta);
else if (smid<x)
Add_sgt(sgt[now].rc,smid+,r,x,y,delta);
else
{
Add_sgt(sgt[now].lc,l,smid,x,smid,delta);
Add_sgt(sgt[now].rc,smid+,r,smid+,y,delta);
}
update(now);
}
void Modify_sgt(int now,int l,int r,int pos,qword v)
{
if (l==r)
{
if (v<)
sgt[now].mx=make_pair(v,l);
else
sgt[now].mx=make_pair(-INFL,-);
sgt[now].sd=v<?-:;
sgt[now].sv=abs(v);
sgt[now].pls=;
return ;
}
down(now,l,r);
if (pos<=smid)
Modify_sgt(sgt[now].lc,l,smid,pos,v);
else
Modify_sgt(sgt[now].rc,smid+,r,pos,v);
update(now);
}
pair<qword,int> Query_sgt_max(int now,int l,int r,int x,int y)
{
if (l==x && r==y)
{
return sgt[now].mx;
}
down(now,l,r);
if (y<=smid)
return Query_sgt_max(sgt[now].lc,l,smid,x,y);
else if (smid<x)
return Query_sgt_max(sgt[now].rc,smid+,r,x,y);
else
return max(Query_sgt_max(sgt[now].lc,l,smid,x,smid),
Query_sgt_max(sgt[now].rc,smid+,r,smid+,y));
}
qword Query_sgt_sum(int now,int l,int r,int x,int y)
{
if (l==x && r==y)
return sgt[now].sv;
down(now,l,r);
if (y<=smid)
return Query_sgt_sum(sgt[now].lc,l,smid,x,y);
else if (smid<x)
return Query_sgt_sum(sgt[now].rc,smid+,r,x,y);
else
return Query_sgt_sum(sgt[now].lc,l,smid,x,smid)+
Query_sgt_sum(sgt[now].rc,smid+,r,smid+,y);
}
struct Edge
{
int np;
Edge *next;
}E[MAXE],*V[MAXV];
int tope=-;
void addedge(int x,int y)
{
E[++tope].np=y;
E[tope].next=V[x];
V[x]=&E[tope];
}
int q[MAXN];
int depth[MAXN],top[MAXN],son[MAXN];
int pnt[MAXN],siz[MAXN];
int pos[MAXN],dfstime;
int spos[MAXN],tpos[MAXN];
void bfs(int now)
{
int head=-,tail=;
Edge *ne;
q[]=now;
depth[now]=;
while (head<tail)
{
now=q[++head];
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==pnt[now])continue;
pnt[ne->np]=now;
depth[ne->np]=depth[now]+;
q[++tail]=ne->np;
}
}
for (int i=tail;i>=;i--)
{
now=q[i];
siz[now]=;
int mxsiz=;
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==pnt[now])continue;
siz[now]+=siz[ne->np];
if (siz[ne->np]>mxsiz)
{
mxsiz=siz[ne->np];
son[now]=ne->np;
}
}
}
}
int stack[MAXN],tops=-;
void dfs(int now)
{
Edge *ne;
memset(spos,0x3f,sizeof(spos));
memset(tpos,,sizeof(tpos));
stack[++tops]=now;
top[now]=now;
while (~tops)
{
now=stack[tops--];
pos[now]=++dfstime;
tpos[top[now]]=max(tpos[top[now]],pos[now]);
spos[top[now]]=min(spos[top[now]],pos[now]);
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==pnt[now] || ne->np==son[now])continue;
stack[++tops]=ne->np;
top[ne->np]=ne->np;
}
if (son[now])
{
stack[++tops]=son[now];
top[son[now]]=top[now];
}
}
}
int troot[MAXN]; int main()
{
freopen("input.txt","r",stdin);
int n,m,x,y,z;
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++)
a[i]=nextInt();
for (int i=;i<n;i++)
{
x=nextInt();y=nextInt();
//scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
bfs();
dfs();
for (int i=;i<=n;i++)
b[pos[i]]=a[i];
for (int i=;i<=n;i++)
{
if (top[i]==i)
Build_sgt(troot[i],spos[i],tpos[i]);
else
troot[i]=-;
}
int opt;
for (int i=;i<m;i++)
{
opt=nextInt();
//scanf("%d",&opt);
if (opt==)
{
x=nextInt();y=nextInt();z=nextInt();
//scanf("%d%d%d",&x,&y,&z);
while (true)
{
if (top[x]==top[y])
{
if (pos[x]>pos[y])swap(x,y);
Add_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pos[x],pos[y],z);
while (true)
{
pair<qword,int> pr;
pr=Query_sgt_max(troot[top[x]],spos[top[x]],tpos[top[x]],pos[x],pos[y]);
if (pr.first<=)break;
Modify_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pr.second,pr.first);
}
break;
}
if (depth[top[x]]<depth[top[y]])swap(x,y);
Add_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pos[top[x]],pos[x],z);
while (true)
{
pair<qword,int> pr;
pr=Query_sgt_max(troot[top[x]],spos[top[x]],tpos[top[x]],pos[top[x]],pos[x]);
if (pr.first<=)break;
Modify_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pr.second,pr.first);
}
x=pnt[top[x]];
}
}else
{
//scanf("%d%d",&x,&y);
x=nextInt();y=nextInt();
qword res=;
while (true)
{
if (top[x]==top[y])
{
if (pos[x]>pos[y])swap(x,y);
res+=Query_sgt_sum(troot[top[x]],spos[top[x]],tpos[top[x]],pos[x],pos[y]);
break;
}
if (depth[top[x]]<depth[top[y]])swap(x,y);
res+=Query_sgt_sum(troot[top[x]],spos[top[x]],tpos[top[x]],pos[top[x]],pos[x]);
x=pnt[top[x]];
}
printf("%lld\n",res);
}
}
}
bzoj 4127: Abs 树链剖分的更多相关文章
- BZOJ 4127: Abs (树链剖分 线段树求区间绝对值之和 带区间加法)
题意 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d(d>=0) 2 u v 表示询问路径 (u,v) 上点权绝对值的和 分析 绝对值之和不好处理,那么我们开 ...
- BZOJ 2243 染色 | 树链剖分模板题进阶版
BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...
- 【BZOJ-4127】Abs 树链剖分 + 线段树 (有趣的姿势)
4127: Abs Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 381 Solved: 132[Submit][Status][Discuss] ...
- BZOJ 3083 遥远的国度 树链剖分
3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 797 Solved: 181[Submit][Status] Descrip ...
- BZOJ 2157: 旅游( 树链剖分 )
树链剖分.. 样例太大了根本没法调...顺便把数据生成器放上来 -------------------------------------------------------------------- ...
- BZOJ 3083: 遥远的国度(树链剖分+DFS序)
可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...
- BZOJ 2157 旅行(树链剖分码农题)
写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v ...
- BZOJ 3083 遥远的国度(树链剖分+LCA)
Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...
- 【bzoj4127】Abs 树链剖分+线段树
题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...
随机推荐
- zTree默认选中指定节点并执行事件
var treeObj = $.fn.zTree.getZTreeObj("treeDemo"); var node = treeObj.getNodeByParam(" ...
- 【二分答案+贪心】UVa 1335 - Beijing Guards
Beijing was once surrounded by four rings of city walls: the Forbidden City Wall, the Imperial City ...
- JAXB - XML Schema Types, Defining an Enumeration
If you want a data type that enumerates discrete values you should use a restriction of the schema t ...
- hyperlink
在list中create column时,注意HyperlinkOrPicture这一选项,如果某一列为HyperLinkOrPicture,那么在后台就不要再加<a></a> ...
- Android res资源文件夹的知识积累
Android的开发框架耦合性还是比较低的,逻辑和布局被原生分开了.在Eclipse一般代码写在src文件夹下,资源等写在res文件夹下. drawable文件夹:该文件夹有很多变种,主要是为了适配A ...
- powerdesigner 使用的几点问题
一.powerdesigner 没有DataBase?: powerdesigner 只有在选择物理模型PDM的时候才会出现数据库菜单. 二.PowerDesigner版本控制功能? 1.首先介绍一下 ...
- 用PL0语言求Fibonacci数列前m个中偶数位的数
程序说明:求Fibonacci数列前m个中偶数位的数: 这是编译原理作业,本打算写 求Fibonacci数列前m个数:写了半天,不会写,就放弃了: 程序代码如下: var n1,n2,m,i; pro ...
- PHP页面间参数传递的四种方法详解
2016-04-16 定义page01.php和page02.php两个php文件,将page01中的内容想办法传递到page02,然后供我们继续使用.------------------------ ...
- 紧跟时代步伐,让我们拥抱MVC 3
作为一个开发者,我们不希望技术很快的更新,这是因为我们还没有完全掌握原来技术的基础上,又要掌握新的技术,作为天天忙忙碌碌的程序员,我们不希望还要额外的时间来学习,尤其是当我们的年龄,逐渐的变大的时候, ...
- 3d旋转--transform-style: preserve-3d,translate3d(x,y,z),perspective()
transform-style: preserve-3d,translate3d(x,y,z),perspective() 让其倾斜的核心:加perspective(600px)让其动的核心:rans ...