专栏文章
题解:P8929 「TERRA-OI R1」别得意,小子
P8929题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minhklif
- 此快照首次捕获于
- 2025/12/02 02:32 3 个月前
- 此快照最后确认于
- 2025/12/02 02:32 3 个月前
题意
有一个分成 段的函数,每一段可能是一次函数或二次函数。有 次询问,每次询问类型有:询问 时函数取值;询问直线 与整段函数的交点个数。
题解
写这道题非常能锻炼二分实现的能力。
一个比较显然的想法是分开处理两类查询。首先我们可以通过二分找到 时对应到哪个函数从而求值。然后我们可以预处理出来若干 ,表示在 时第二类查询的答案为 。这样枚举每一段函数,计算对总答案的贡献即可。
但是直接做需要大量的分类讨论。怎么办呢?我们发现可以把分段函数进一步分割成若干单调区间,单调区间对答案的贡献非常好计算,就是一个区间加一。分类讨论如下(以下区间指的是值域上的区间):
- 一次函数,设左右函数值为 ,如果 ,分成区间 ,否则分成区间 。
- 二次函数,设左右函数值为 ,顶点坐标为 。讨论顶点是否取得到。如果 ,就分成两个区间考虑,否则就是分成一个区间。如果分成两个区间,且 ,分成的区间是 和 ; 分成的区间是 和 。如果分成一个区间,且 ,分成的区间是 ,否则是 。
到这一步就可以把分出来的区间差分算贡献了。我的做法是:分成下界 和上界 ,每次查询时计算 即可。
CPP#include<iostream>
#include<vector>
#include<set>
#include<climits>
#include<algorithm>
using namespace std;
struct node{
long long a,b,c;
double l,r;//覆盖区间(l,r]
}a[2000001];
int acnt;
constexpr long double eps=1e-8;
vector<pair<pair<double,double>,int>> v;
int n,q;
//second=-1 取得到 1 取不到
pair<long double,int> v1[2000001],v2[2000001];//v1为下界 v2为上界
int cnt1,cnt2;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> q;
for(int i=1;i<=n;i++){
int l,r,op;
cin >> l >> r >> op;
if(op==1){
long long b,c;
cin >> b >> c;
a[++acnt]=node({0,b,c,l+0.0,r+0.0});
if(b>0){
v1[++cnt1]={b*l+c,1};
v2[++cnt2]={b*r+c,-1};
} else{
v1[++cnt1]={b*r+c,-1};
v2[++cnt2]={b*l+c,1};
}
} else{
long long a,b,c;
cin >> a >> b >> c;
double mx=-b/(2.0l*a);
long double my=c-((long double)(b)*b)/(4.0l*a);
long double ml=((long double)(a)*l+b)*l+c,mr=((long double)(a)*r+b)*r+c;
if(l<=mx && mx<=r){
::a[++acnt]=node({a,b,c,l+0.0,mx});
::a[++acnt]=node({a,b,c,mx,r+0.0});
if(a>0){
v1[++cnt1]={my,-1};
v1[++cnt1]={my,1};
v2[++cnt2]={ml,1};
v2[++cnt2]={mr,-1};
} else{
v2[++cnt2]={my,-1};
v2[++cnt2]={my,1};
v1[++cnt1]={ml,1};
v1[++cnt1]={mr,-1};
}
} else{
::a[++acnt]=node({a,b,c,l+0.0,r+0.0});
if(ml<mr){
//(ml,mr]
v1[++cnt1]={ml,1};
v2[++cnt2]={mr,-1};
} else{
//[mr,ml)
v1[++cnt1]={mr,-1};
v2[++cnt2]={ml,1};
}
}
}
}
for(int i=1;i<=acnt;i++){
v.push_back(make_pair(make_pair(a[i].l,a[i].r),i));
}
for(int i=1;i<=cnt2;i++){
v2[i].second=-v2[i].second;
}
sort(v1+1,v1+cnt1+1);
sort(v2+1,v2+cnt2+1);
while(q--){
int op;
long long k;
cin >> op >> k;
if(op==1){
int i=(--lower_bound(v.begin(),v.end(),make_pair(make_pair(k+0.0,0.0),INT_MAX)))->second;
cout << (a[i].a*k+a[i].b)*k+a[i].c << '\n';
} else{
int li=((upper_bound(v1+1,v1+cnt1+1,make_pair(k+0.0l,0)))-v1);
int ri=((lower_bound(v2+1,v2+cnt2+1,make_pair(k+0.0l,0)))-v2);
//下界小于等于k的 - 上界小于k的
cout << li-ri << '\n';
}
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...