题目描述

给定一棵树,设计数据结构支持以下操作
1 u v d  表示将路径 (u,v) 加d
2 u v  表示询问路径 (u,v) 上点权绝对值的和

输入

第一行两个整数n和m,表示结点个数和操作数
接下来一行n个整数a_i,表示点i的权值接下来n-1行,每行两个整数u,v表示存在一条(u,v)的边接下来m行,每行一个操作,输入格式见题目描述

输出

对于每个询问输出答案

样例输入

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

样例输出

10
13
9

提示

对于100%的数据,n,m <= 10^5 且 0<= d,|a_i|<= 10^8

如果都是正数直接树链剖分+线段树就行了。

现在有了负数,那不是再维护一个区间正数个数就好了?显然是不够的。

因为区间修改时会把一些负数变为正数,会改变区间正数的个数,所以我们要维护区间三个值:

1、区间绝对值之和

2、区间非负数个数

3、区间最大的负数

当每次修改一个区间时如果这个区间的最大负数会变成非负数,那么说明这个区间的非负数个数会改变,因此要重构这个区间。

怎么重构呢?

对于这个区间的左右子区间,对于不需要重构的子区间下传标记,对于需要重构的子区间就递归重构下去。

因为每个数最多只会被重构一次,因此重构均摊O(nlogn)。总时间复杂度还是O(mlogn)级别。

#include<set>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int num[800010];
int mx[800010];
ll sum[800010];
int d[100010];
int f[100010];
int son[100010];
int size[100010];
int top[100010];
int to[200010];
int tot;
int head[100010];
int s[100010];
int q[100010];
int n,m;
int x,y,z;
int opt;
int cnt;
ll a[800010];
int next[200010];
int v[100010];
int merge(int x,int y)
{if(x<0&&y<0){return max(x,y);}if(x<0){return x;}if(y<0){return y;}return 0;
}
void add(int x,int y)
{tot++;next[tot]=head[x];head[x]=tot;to[tot]=y;
}
void dfs(int x)
{size[x]=1;d[x]=d[f[x]]+1;for(int i=head[x];i;i=next[i]){if(to[i]!=f[x]){f[to[i]]=x;dfs(to[i]);size[x]+=size[to[i]];if(size[to[i]]>size[son[x]]){son[x]=to[i];}}}
}
void dfs2(int x,int tp)
{s[x]=++cnt;top[x]=tp;q[cnt]=x;if(son[x]){dfs2(son[x],tp);}for(int i=head[x];i;i=next[i]){if(to[i]!=f[x]&&to[i]!=son[x]){dfs2(to[i],to[i]);}}
}
void pushup(int rt)
{num[rt]=num[rt<<1]+num[rt<<1|1];sum[rt]=sum[rt<<1]+sum[rt<<1|1];mx[rt]=merge(mx[rt<<1],mx[rt<<1|1]);
}
void pushdown(int rt,bool x,bool y,int l,int r)
{if(a[rt]){int mid=(l+r)>>1;if(x){if(mx[rt<<1]){mx[rt<<1]+=a[rt];}sum[rt<<1]+=1ll*(2*num[rt<<1]-(mid-l+1))*a[rt];a[rt<<1]+=a[rt];}if(y){if(mx[rt<<1|1]){mx[rt<<1|1]+=a[rt];}sum[rt<<1|1]+=1ll*(2*num[rt<<1|1]-(r-mid))*a[rt];a[rt<<1|1]+=a[rt];}a[rt]=0;}
}
void build(int rt,int l,int r)
{if(l==r){if(v[q[l]]<0){mx[rt]=v[q[l]];}else{num[rt]=1;}sum[rt]=abs(v[q[l]]);return ;}int mid=(l+r)>>1;build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);pushup(rt);
}
void rebuild(int rt,int l,int r,ll c)
{if(l==r){num[rt]=1;sum[rt]=mx[rt]+c;mx[rt]=0;return ;}int mid=(l+r)>>1;c+=a[rt];a[rt]=c;if(mx[rt<<1]&&mx[rt<<1]+c>=0&&mx[rt<<1|1]&&mx[rt<<1|1]+c>=0){a[rt]=0;rebuild(rt<<1,l,mid,c);rebuild(rt<<1|1,mid+1,r,c);}else if(mx[rt<<1]&&mx[rt<<1]+c>=0){pushdown(rt,0,1,l,r);rebuild(rt<<1,l,mid,c);}else if(mx[rt<<1|1]&&mx[rt<<1|1]+c>=0){pushdown(rt,1,0,l,r);rebuild(rt<<1|1,mid+1,r,c);}pushup(rt);
}
void change(int rt,int l,int r,int L,int R,int c)
{if(L<=l&&r<=R){if(mx[rt]+c>=0&&mx[rt]){rebuild(rt,l,r,c);}else{if(mx[rt]){mx[rt]+=c;}a[rt]+=c;sum[rt]+=1ll*(2*num[rt]-(r-l+1))*c;}return ;}int mid=(l+r)>>1;pushdown(rt,1,1,l,r);if(L<=mid){change(rt<<1,l,mid,L,R,c);}if(R>mid){change(rt<<1|1,mid+1,r,L,R,c);}pushup(rt);
}
ll query(int rt,int l,int r,int L,int R)
{if(L<=l&&r<=R){return sum[rt];}pushdown(rt,1,1,l,r);int mid=(l+r)>>1;long long res=0;if(L<=mid){res+=query(rt<<1,l,mid,L,R);}if(R>mid){res+=query(rt<<1|1,mid+1,r,L,R);}return res;
}
void updata(int x,int y,int z)
{while(top[x]!=top[y]){if(d[top[x]]<d[top[y]]){swap(x,y);}change(1,1,n,s[top[x]],s[x],z);x=f[top[x]];}if(d[x]>d[y]){swap(x,y);}change(1,1,n,s[x],s[y],z);
}
ll downdata(int x,int y)
{ll res=0;while(top[x]!=top[y]){if(d[top[x]]<d[top[y]]){swap(x,y);}res+=query(1,1,n,s[top[x]],s[x]);x=f[top[x]];}if(d[x]>d[y]){swap(x,y);}res+=query(1,1,n,s[x],s[y]);return res;
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&v[i]);}for(int i=1;i<n;i++){scanf("%d%d",&x,&y);add(x,y);add(y,x);}dfs(1);dfs2(1,1);build(1,1,n);while(m--){scanf("%d",&opt);scanf("%d%d",&x,&y);if(opt==1){scanf("%d",&z);updata(x,y,z);}else{printf("%lld\n",downdata(x,y));}}
}

转载于:https://www.cnblogs.com/Khada-Jhin/p/9699973.html

BZOJ4127Abs——树链剖分+线段树相关推荐

  1. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1153  Solved: 421 [Submit][Sta ...

  2. BZOJ3862Little Devil I——树链剖分+线段树

    题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...

  3. CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...

  4. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  5. P2486 [SDOI2011]染色(树链剖分+线段树)

    题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q ...

  6. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  7. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  8. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  9. YbtOJ-染色计划【树链剖分,线段树,tarjan】

    正题 题目大意 给出nnn个点的一棵树,每个点有个颜色aia_iai​,你每次可以选择一个颜色全部变成另一个颜色. 求最少多少次操作可以把一种颜色变成一个完整的连通块. 1≤k≤n≤2×1051\le ...

最新文章

  1. 部分 II. Network
  2. mhk科技计算机报名时间,2021计算机等级考试报名时间
  3. python工作招聘-python爬虫 智联招聘 工作地点
  4. Windows Azure: Blob Container的访问权限与策略设置
  5. 分割文本_PSENet、PANNet、DBNet三个文本检测算法异同
  6. c++创建二叉树_数据结构:查找(4)|| 平衡二叉树
  7. 如何重构千行“又臭又长”的类,IntelliJ IDEA 几分钟搞定!
  8. windows 根据端口杀死进程
  9. 如何在Exchange 2013中禁用对ECP的外部访问
  10. paip.python错误解决23
  11. vscode使用教程-开始学习前端开发啦~
  12. c语言 公式编辑器,AxMath(公式计算编辑器)
  13. SLAM学习 | 使用小觅相机MYNTEYE-S1030收集数据集
  14. 服务器域名解析问题,域名解析出现错误的几种情况,以及解决方法
  15. PHPStorm的资料网址
  16. java适合音频格式_我应该为java使用什么音频格式?
  17. 运城学院计算机课,运城学院微机原理与应用精品课程
  18. Allegro Shape菜单详解
  19. 存储系统——主存储器
  20. 由LG 的G2手机浅析国产旗舰机的方向

热门文章

  1. ruby 生成哈希值_哈希== Ruby中的运算符
  2. kafka数据不丢失不重复_超高速底层系统数据复制,安全精准不丢失
  3. mysql主从同步面试题_面试被问MySQL 主从复制,怎么破?
  4. UVA 10453—— Make Palindrome
  5. C++迭代器使用错误总结
  6. 【蓝桥杯】BASIC-8 回文数(2020-06-08)
  7. shell编程题(二)
  8. 九大经典算法之选择排序、堆排序
  9. 1059 Prime Factors(25 分)
  10. 【C++ Primer | 13】课后习题答案