线段树&树状数组与离散化的妙用
牛客2019多校联盟Day7 Fine the median
题意: 每次给数组插入区间[Li,Ri] 内的所有数,每操作一次查询中位数。
遇到这题真的算是巧合,然而就是这种冥冥之中的缘分,给了我线段树的一个全新的思想。
这题与以往的线段树做法有所不同,常规的线段树题目,可能就是一个点区间代表一个数据,然后找个区间最大值什么的。
这种很显而易见的,对吧?因为点区间代表了一个点,仅仅是一个点,所以做起来比较容易。
而今天这题十分有趣。它的点区间代表的是一个区间。
比如这题,我们去怎么解决呢?
对于更新,所有要加入的区间,我们先离散化。比如我们要加【1,3】【3,6】 .去重之后的数组就是【1,3,6】,之后处理【1,3】这个操作的时候,直接lower_bound定位他在离散数组里面的那个位置,以这个位置做为线段树的建树和后续查询的依据。
对于查询,我们要定义一个数组代表线段树里面的某个区间加了多少个数。如果左子区间的个数大于中位数所在的位置,就去左子区间;如果右子区间的个数大于中位数所在的位置,那么我们就把中位数所在的位置减去左子区间的个数。
其实这题妙在线段树与离散化数组构成的联系,线段树的区间就是刚好对应了离散数组的位置。详情看代码
#include <bits/stdc++.h>
#define maxn 400005
using namespace std;
typedef long long ll;
int i,n,zuo,you;
ll sum,x[maxn],y[maxn],A1,A2,B1,B2,C1,C2,M1,M2,a[maxn*],lazy[maxn*],G[maxn*],L[maxn],R[maxn];
void push_up(int num)
{
a[num]=a[num*]+a[num*+];
}
void push_down(int l,int r,int num)
{
if (lazy[num]==) return;
int mid=(l+r)/;
lazy[num*]+=lazy[num];
lazy[num*+]+=lazy[num];
a[num*]+=(G[mid+]-G[l])*lazy[num];
a[num*+]+=(G[r+]-G[mid+])*lazy[num];
lazy[num]=;
}
void upgrade(int l,int r,int num)
{
if (zuo<=l && r<=you)
{
lazy[num]+=;
a[num]+=G[r+]-G[l];
return;
}
push_down(l,r,num);
int mid=(l+r)/;
if (mid>=zuo) upgrade(l,mid,num*);
if (mid<you) upgrade(mid+,r,num*+);
push_up(num);
}
ll query(int l,int r,int num,ll sum)
{
if (l==r)
{
int ti=a[num]/(G[r+]-G[l]);
return G[l]+(sum-)/ti;
}
push_down(l,r,num);
int mid=(l+r)/;
if (a[num*]>=sum) return query(l,mid,num*,sum);
else return query(mid+,r,num*+,sum-a[num*]);
}
int main()
{
cin>>n;
scanf("%lld%lld%lld%lld%lld%lld",&x[],&x[],&A1,&B1,&C1,&M1);
scanf("%lld%lld%lld%lld%lld%lld",&y[],&y[],&A2,&B2,&C2,&M2);
for (i=;i<=n;i++)
{
x[i]=(A1*x[i-]+B1*x[i-]+C1)%M1;
y[i]=(A2*y[i-]+B2*y[i-]+C2)%M2;
}
for (i=;i<=n;i++)
{
L[i]=min(x[i],y[i])+;
R[i]=max(x[i],y[i])++;
G[i]=L[i];
G[i+n]=R[i];
}
sort(G+,G++*n);
int element=unique(G+,G++*n)-G-;
for (i=;i<=n;i++)
{
sum+=R[i]-L[i];
zuo=lower_bound(G+,G++element,L[i])-G;
you=lower_bound(G+,G++element,R[i])-G-;
upgrade(,element,);
printf("%lld\n",query(,element,,(sum+)/));
}
return ;
}
CF round 624 F
看到这题的时候就感觉有些熟悉,但是树状数组写的很少,于是一开始就想着用线段树去解决,然后看了看数据范围,感觉线段树很有可能会爆,于是匆匆收场。
其实当时我还想着一个比较傻b的问题,A点在B点后面,速度比B要大,相隔距离最短的时候是多少米。对,没错,这道高中物理送分题,我竟然想了一段时间。枯了
我们可以看到有两种情况
一个点在另一个点的后面,速度比它小,那么相隔距离最短的时候就是0秒的时候
一个点在另一个点的后面,速度比它大,那么它们两个一定能相遇!
所以我们把点的坐标、速度分别从小到大排序。我们这里不用查重,因为查重之后就找不到对应的位置了。
以点的大小为依据,又分两种情况
一个是速度为负,一个是速度为正,对于两点之间速度相反的点,我们直接相加和他们的初始的距离。这里可能会有疑问?如果当前处理的点速度为正,下一个要循环的点速度为负且这个点在当前点的右边,那么它们不会相遇吗?这里我们进行一个处理,对于速度为负的点,我们只处理与速度为负的其他点的关系;对于速度为正的点,我们就全部处理。
那么速度相向的问题解决了,速度方向相同呢?
如果0s的时候是最佳答案,我们把当前点的速度就存在树状数组里,我们在下一个点的处理,把两点之间距离加上。
我们要清楚这里是标量之间比较大小,所以数字小的速度肯定会被数字大的速度累加到,累加这个过程就有点前缀和的味道,具体看程序。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
struct node
{
int x,v;
};
const int N = 2e5 + ;
node a[N];
int n,i,v[N];
ll z[N], f[N], zhsum[N], fusum[N],num,ans;
bool cmp(node x,node y)
{
return x.x<y.x;
}
int lowbit(int x)
{
return x & (-x);
}
ll sum(int x,ll d[])
{
ll cnt=;
while (x)
{
cnt+=d[x];
x-=lowbit(x);
}
return cnt;
}
void add(int x,int k,ll d[])
{
while (x<N)
{
d[x]+=k;
x+=lowbit(x);
}
}
int main()
{
scanf("%d",&n);
for (i=;i<=n;i++) scanf("%d",&a[i].x);
for (i=;i<=n;i++)
{
scanf("%d",&a[i].v);
v[i]=a[i].v;
}
sort(v+,v++n);
sort(a+,a++n,cmp);
for (i=;i<=n;i++)
{
if (a[i].v<)
{
num=lower_bound(v+,v++n,a[i].v)-v;
ans+=sum(num,fusum)*a[i].x-sum(num,f);
add(num,a[i].x,f);
add(num,,fusum);
}
else
{
num=lower_bound(v+,v++n,a[i].v)-v;
ans+=sum(N-,fusum)*a[i].x-sum(N-,f);
ans+=sum(num,zhsum)*a[i].x-sum(num,z);
add(num,a[i].x,z);
add(num,,zhsum);
}
}
cout<<ans<<endl;
return ;
}
线段树&树状数组与离散化的妙用的更多相关文章
- WUSTOJ 1337: Car race game(C)树状数组,离散化
题目链接:1337: Car race game 参考资料:⑴ Car race game 树状数组 棋煜,⑵ 树状数组,⑶ 离散化 补充资料:⑴ qsort,⑵ 二分查找 Description B ...
- HDU 4605 Magic Ball Game(可持续化线段树,树状数组,离散化)
Magic Ball Game Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- D. Nested Segments(树状数组、离散化)
题目链接 参考博客 题意: 给n个线段,对于每个线段问它覆盖了多少个线段. 思路: 由于线段端点是在2e9范围内,所以要先离散化到2e5内(左右端点都离散化了,而且实际上离散化的范围是4e5),然后对 ...
- HDU 3333 | Codeforces 703D 树状数组、离散化
HDU 3333:http://acm.hdu.edu.cn/showproblem.php?pid=3333 这两个题是类似的,都是离线处理查询,对每次查询的区间的右端点进行排序.这里我们需要离散化 ...
- POJ-2299 Ultra-QuickSort (树状数组,离散化,C++)
Problem Description In this problem, you have to analyze a particular sorting algorithm. The algorit ...
- HDU 5877 Weak Pair(树状数组+dfs+离散化)
http://acm.hdu.edu.cn/showproblem.php?pid=5877 题意: 给出一棵树,每个顶点都有权值,现在要你找出满足要求的点对(u,v)数,u是v的祖先并且a[u]*a ...
- 【(待重做)树状数组+dp+离散化】Counting Sequences
https://www.bnuoj.com/v3/contest_show.php?cid=9149#problem/G [题意] 给定一个数组a,问这个数组有多少个子序列,满足子序列中任意两个相邻数 ...
- 算法笔记求序列A每个元素左边比它小的数的个数(树状数组和离散化)
#include <iostream> #include <algorithm> #include <cstring> using namespace std ; ...
- The 2015 China Collegiate Programming Contest -ccpc-c题-The Battle of Chibi(hdu5542)(树状数组,离散化)
当时比赛时超时了,那时没学过树状数组,也不知道啥叫离散化(貌似好像现在也不懂).百度百科--离散化,把无限空间中无限的个体映射到有限的空间中去,以此提高算法的时空效率. 这道题是dp题,离散化和树状数 ...
随机推荐
- luffy 那点事
1 虚拟环境创建 2 后台:Django项目创建 3 后台配置 4 数据库配置 5 user模块User表 6 前台 7 前台配置 8 前端主页 9 后端主页模块设计 10 xadmin 后台管理 1 ...
- JS监听手机物理返回键,返回到指定页面
pushHistory(); window.addEventListener("popstate", function(e) { window.location = data.in ...
- SIM800L AT command
/*********************************************************** AT+ICF==<format> ,<parity> ...
- ASM ClassReader failed to parse class file
ASM ClassReader failed to parse class file - probably due to a new Java class file version that isn' ...
- [7b2美化]柒比贰 魔改系列|7B2-分类封面添加波浪效果&每日诗词
本文转载自:钻芒博客 https://www.zmki.cn/5105.html 效果如图: 代码: 首先在style.css样式表里添加波浪样式 /*浪来了*/ .lang { overflow: ...
- Python format语法
a = {"name" : "alex","age":16} v = "my name is {name}, my age is ...
- delphi窗体按钮灰化禁用
1.使最小化按钮变灰:setwindowlong(handle,gwl_style,getwindowlong(handle,gwl_style) and not ws_minimizeb ...
- 十九 Listener
Listener 监听器 一 监听器内部原理:其实就是接口回调 需求:A在执行循环,当循环到5的时候,通知B 事先先把某一个对象传递给A ,当A执行到5的时候,通过这个对象来调用B中的方法 但是不是直 ...
- JuJu团队1月9号工作汇报
JuJu团队1月9号工作汇报 JuJu Scrum 团队成员 今日工作 剩余任务 困难 飞飞 将示例程序打包成exe 将crossentrophy和softmax连接起来 无 婷婷 -- 完善ma ...
- arm linux 移植 OpenCV
背景: 由于学习了摄像头有关的开发,顺理成章地接触了这个部分. 搭建环境 openCV 2.2以后版本需要使用Cmake生成makefile文件,因此需要先安装cmake. OpenCV : v4.2