[机房测试]WC

Description

西比拉系统正在观察一个人的心理。
这个人的心理可以抽象为一条数轴,上面存在一些非负整点,被称为「意识」。
观察的方式是选取一个非负整点作为采样点,尝试捕捉这个点附近的意识。
对于一次采样,西比拉系统会吸引在区间 \([l,r]\) 内的意识,这时意识会向采样点靠近,此处的 \([l,r]\) 称为这次采样的吸引区间。
每次采样又会有一个参数,捕捉半径 \(t\),表示如果有意识可以被吸引而移动到 \([x1-t,x1+t]\) 范围内,其数据就会被捕捉。其中 \(x1\) 表示采样点的位置。
注意,当一次采样结束,所有意识都会回到原来的位置。
每个意识会有一个参数,思维强度 \(s\),表示这个意识被吸引时的可移动范围为 \([x2-s,x2+s]\),其中 \(x2\) 表示这个意识出现的位置。
初始时数轴上没有意识,此后每个时刻仅会发生一个事件。
事件有两种:
·意识事件,形如 \(T \ x2 \ s\),表示在 \(x2\) 处出现了一个思维强度为 \(s\) 的意识。
·采样事件,形如 \(G \ x1 \ l \ r \ t\),表示在 \(x1\) 处进行一次吸引区间为 \([l,r]\),捕捉半径为 \(t\),请求出会被捕捉到的意识的个数。
对于每次采样,请求出会被捕捉到的意识的个数。

Solution

容易发现,就是需要统计满足条件

\[\begin{cases} |x_1-x_2|\leq t+s \\ l\leq x_2 \leq r \end{cases} \]

的点的个数。按照套路,把绝对值拆开,可以得到两种限制条件

\[\begin{cases} x_1<x_2\leq r \\ x_2-s\leq t+x_1 \end{cases} \text{or}\ \begin{cases} l\leq x_2 \leq x_1\\ x_2+s\geq x_1-t \end{cases} \]

加上时间限制,跑两遍CDQ分治即可,内层用平衡树查区间数的个数。

考场代码写得有点不一样,是把询问差分了,但是是一个道理。

#include<stdio.h>
#include<algorithm>
#include<stdlib.h>
using namespace std;

inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}

const int N=2e5+7;

struct Que{
    int pos,x,s; bool op; int P;
    Que(int pos_=-1,int x_=0,int s_=0,bool op_=0,int P_=0):
        pos(pos_),x(x_),s(s_),op(op_),P(P_){}
}a[N];

struct Node{
    int sz,key,ls,rs,val;
}t[N];

int top=0,rev[N],tp=0,ans[N];

inline bool Cmp1(const Que &X,const Que &Y){
    int x=X.x,y=Y.x;
    if(~X.pos) x=min(x,X.pos);
    if(~Y.pos) y=min(y,Y.pos);
    return x<y;
}

inline bool Cmp2(const Que &X,const Que &Y){
    int x=(~X.pos)? X.x+X.s:X.x-X.s;
    int y=(~Y.pos)? Y.x+Y.s:Y.x-Y.s;
    return x<y;
}

void Del(int id){
    if(t[id].ls) Del(t[id].ls);
    if(t[id].rs) Del(t[id].rs);
    rev[++tp]=id;
}

inline int New(int x){
    static int cnt=0; int p;
    if(tp) p=rev[tp--];
    else p=++cnt;
    t[p]=(Node){1,rand(),0,0,x};
    return p;
}

inline void update(int id){
    t[id].sz=t[t[id].ls].sz+t[t[id].rs].sz+1;
}

int merge(int x,int y){
    if(!x||!y) return x+y;
    if(t[x].key<t[y].key){
        t[x].rs=merge(t[x].rs,y);
        return update(x),x;
    }else{
        t[y].ls=merge(x,t[y].ls);
        return update(y),y;
    }
}

void split(int id,int k,int &x,int &y){
    if(!id){x=y=0;return;}
    if(t[id].val<=k)
        x=id,split(t[id].rs,k,t[id].rs,y);
    else y=id,split(t[id].ls,k,x,t[id].ls);
    update(id);
}

void CDQ(int lf,int rf){
    if(lf==rf) return ;
    int mid=(lf+rf)>>1;
    CDQ(lf,mid),CDQ(mid+1,rf);
    sort(a+lf,a+mid+1,Cmp1),sort(a+mid+1,a+rf+1,Cmp1);
    int rt=0,x,y,z;
    for(int i=mid+1,j=lf;i<=rf;i++){
        if(a[i].pos==-1) continue;
        const int rg=min(a[i].pos,a[i].x);
        while(j<=mid&&((~a[j].pos)||(a[j].x<=rg))){
            if(~a[j].pos){j++;continue;}
            split(rt,a[j].x+a[j].s,x,y);
            rt=merge(merge(x,New(a[j].x+a[j].s)),y);
            j++;
        }
        split(rt,a[i].x-a[i].s-1,x,y);
        ans[a[i].P]+=(a[i].op? 1:-1)*t[y].sz;
        rt=merge(x,y);
    }
    if(rt) Del(rt); rt=0;
    sort(a+lf,a+mid+1,Cmp2),sort(a+mid+1,a+rf+1,Cmp2);
    for(int i=mid+1,j=lf;i<=rf;i++){
        if(a[i].pos==-1) continue;
        if(a[i].x>=a[i].pos) continue;
        const int rg=a[i].x+a[i].s;
        while(j<=mid&&((~a[j].pos)||(a[j].x-a[j].s<=rg))){
            if(~a[j].pos){j++;continue;}
            split(rt,a[j].x,x,y);
            rt=merge(merge(x,New(a[j].x)),y);
            j++;
        }
        split(rt,a[i].pos,y,z);
        split(y,a[i].x,x,y);
        ans[a[i].P]+=(a[i].op? 1:-1)*t[y].sz;
        rt=merge(merge(x,y),z);
    }
    if(rt) Del(rt);
}

int main(){
    freopen("mind.in","r",stdin);
    freopen("mind.out","w",stdout);
    srand(114514);
    int n=read(),q=0; char op[5];
    for(int i=1;i<=n;i++){
        scanf("%s",op);
        if(op[0]=='T'){
            int x=read()+1,s=read();
            a[++top]=Que(-1,x,s);
        }else{
            q++;
            int x=read()+1,l=read()+1,r=read()+1,s=read();
            a[++top]=Que(l-1,x,s,0,q),a[++top]=Que(r,x,s,1,q);
        }
    }
    CDQ(1,top);
    for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
}
posted @ 2021-10-20 08:50  Kreap  阅读(61)  评论(0编辑  收藏  举报