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,表示结点个数和操作数 ...
随机推荐
- hdu 1093 A+B for Input-Output Practice (V)
A+B for Input-Output Practice (V) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/3276 ...
- 世界上最方便的SharePoint移动客户端--Rshare
Rshare我试用了一段时间,同时也测试了其他家产品,使用后的感觉是Rshare无愧于世界上最方面的SharePoint移动客户端. 1.界面设计很方便,设计中充分考虑到移动客户的使用习惯及喜好,设计 ...
- PHP之基本语法
人生最幸福的事之一就是,邻居家的wifi密码是123456789,于是回家在pad上也照样可以扯淡.任何语言都有自己的语法,这里只简单说些我觉得应该注意的地方. 首先要明白,PHP是运行于服务器端的脚 ...
- 【转载】最近在用Arrays的asList()生成的List时,List元素的个数时而不正确,数组转化为List,即Arrays.asList(intArray);
最近在用Arrays的asList()生成的List时,List元素的个数时而不正确. Java代码 //经多次测试,只要传递的基本类型的数组,生成List的元素个数均为1 char arrc = { ...
- linux---基本查找命令
基本查找命令 一.文件查找命令:find 最大特点:功能强大,可以使用文件的各种属性作为查找条件来查找文件 文件属性:文件权限.文件所有者.文件大小.修改时间.文件类型 语法:find[起始查找目录] ...
- 一个类似repo的小程序
#! /usr/bin/env python # -*- coding: utf-8 -*- # usage : python EasyRepo.py -u "13051041" ...
- Android之 Fragment
什么是Fragment: Android是在Android 3.0 (API level 11)开始引入Fragment的. 可以把Fragment想成Activity中的模块,这个模块有自己的布局, ...
- (poj)1806 Currency Exchange
题目链接:http://poj.org/problem?id=1860 Description Several currency exchange points are working in our ...
- VC++ CTime Format 详解
参考链接: VC++中CTime类Format参数详解 CTime/COleDateTime::Format方法的使用 http://stat.ethz.ch/R-manual/R-devel/lib ...
- 信息收集->DNS分析->dnsdict6
如何获取域名的IPV4/IPV6地址之dnsdict6的使用 dnsdict6是一个用于获取网站信息的工具.dnsdict6可以扫描网站并显示有多少域或者子域,也可以扫描ipv6/ipv4地址.dns ...