zoukankan      html  css  js  c++  java
  • [机房测试]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]);
    }
    
  • 相关阅读:
    DataGird导出EXCEL的几个方法
    csv文件与DataTable互相导入处理
    LeetCode 345
    LeetCode 168
    LeetCode 344
    LeetCode 342
    LeetCode 343
    LeetCode 326
    LeetCode 338
    LeetCode 319
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/15427263.html
Copyright © 2011-2022 走看看