关于此题线段树数组大小
查看原帖
关于此题线段树数组大小
177000
vicky2048_2楼主2023/9/20 22:20

rt

我怎么证都是应该开 xx 的取值范围([1,40000][1,40000])的两倍就够了,而且线段树数组开两倍交上去也AC了

但还是有点怀疑自己是不是证错了

代码:(这一份是我的复习版代码,所以可能多少带点注释……QAQ)

#include<bits/stdc++.h>
#define int long long
#define N 100005
#define X 40005
#define esp 1e-8
#define modx 39989
#define mody 1000000000
using namespace std;
int n,bh,cnt,ans,no;
double cal(int,int);
struct tree{
    int l,r,id;
}tr[X<<1];//只需要开x的取值范围的倍即可
struct E{
    double st,k;
    E(double a=0,double b=0){ st=a,k=b;}
}e[N];
int ask(int,int,int,int);
void insert(int&,int,int,int,int,int);
bool com(int,int,int);
signed main(){
    scanf("%lld",&n);
    while(n--){
        int op,k,x0,x1,y0,y1;
        scanf("%lld",&op);
        if(!op)
            scanf("%lld",&k),
            ans=ask(1,1,X,(k+ans-1)%modx+1),
            printf("%lld\n",ans);
        else{
            scanf("%lld%lld%lld%lld",&x0,&y0,&x1,&y1);
            x0=(x0+ans-1)%modx+1,x1=(x1+ans-1)%modx+1;
            y0=(y0+ans-1)%mody+1,y1=(y1+ans-1)%mody+1;
            if(x0>x1)
                swap(x0,x1),swap(y0,y1);
            if(x0==x1)
                e[++cnt]=E(max(y1,y0),0);//这里记得取max
            else{
                double k=1.0*(y1-y0)/(x1-x0);//记得转double
                e[++cnt]=E(1.0*y0-1.0*x0*k/*这里记得减去x0*k,不然后面计算时会算两遍x0*k!!!*/,k);
            }
            insert(no,1,X,x0,x1,cnt);
        }
    }
    return 0;
}
bool com(int a,int b,int x){//若线段a比线段b更优,则返回true
    double num1=cal(a,x),num2=cal(b,x);
    if(abs(num1-num2)<esp)//减小被卡精度的可能
        return a<b;
    return num1>num2;
}
double cal(int id,int x){
    return 1.0*e[id].k*x+e[id].st;//老生常谈转double
}
int ask(int no,int l,int r,int x){
    if(!no) return 0;//若该区间不存在线段,则直接返回
    if(l==r) return tr[no].id;
    int ans=0,mi=l+r>>1;
    if(x<=mi)//不断地取点x经过的区间中的最优线段
        ans=ask(tr[no].l,l,mi,x);
    else
        ans=ask(tr[no].r,mi+1,r,x);
    if(com(tr[no].id,ans,x))//之前经过的小区间的最优线段与当前区间的最优线段进行比较
        ans=tr[no].id;
    return ans;
}
void insert(int &no,int l,int r,int x1,int x2,int id){
    if(!no)
        no=++bh;//若当前区间没有编号,则给当前区间进行编号,记得打函数参数中的“&”,不然改了之后返回之前的区间就等于啥也没改了!!!
    int mi=l+r>>1;
    if(x1<=l&&x2>=r){
        if(com(tr[no].id,id,l)&&com(tr[no].id,id,r))
            return ;//左右两边都不优,直接舍
        if(com(id,tr[no].id,l)&&com(id,tr[no].id,r)){//左右两边都为当前最优,则用线段id直接覆盖该区间
            tr[no].id=id;
            return ;
        }
        if(com(id,tr[no].id,mi)) swap(tr[no].id,id);//若线段id在mid处更优,则更新no的线段,并判断线段id在左右两子区间是否可能更优
        if(com(id,tr[no].id,l)) insert(tr[no].l,l,mi,x1,x2,id);
        //左端点更大,可能取到更优;
        //注意!这里不能判断左区间的mid值,因为即使左区间的mid处值更劣,线段id也可能在左区间的子区间的mid处更优
        else insert(tr[no].r,mi+1,r,x1,x2,id);
    }
    else{
        if(x1<=mi)
            insert(tr[no].l,l,mi,x1,x2,id);
        if(x2>mi)
            insert(tr[no].r,mi+1,r,x1,x2,id);
    }
}
2023/9/20 22:20
加载中...