【BZOJ】5462: [APIO2018] 新家-二分+线段树+multiset

传送门:bzoj5462


题解

orzkczno1奆佬
这个 n log ⁡ n n\log n nlogn的做法好妙呀(不想写线段树分治了


代码

#include<bits/stdc++.h>
#define fi first
#define sc second
#define pb push_back
//#define ccosi
using namespace std;
const int N=3e5+10,MX=1e9;
typedef long long ll;
typedef double db;

int n,K,m,cnt,ans[N];
int v[N],num,as;

struct qr{
    int pos,typ,tim,op;
    bool operator<(const qr&ky)const{
       if(tim!=ky.tim) return tim<ky.tim;
       return op<ky.op;
    }
}a[N*3];

#ifndef ccosi
char buf[(1<<15)];int p1=0,p2=0;
inline char gc()
{
  if(p1==p2) p1=0,p2=fread(buf,1,(1<<15),stdin);
  return (p1==p2)?EOF:buf[p1++];
}
#endif

#ifdef ccosi
#define gc getchar
#endif

char cp;
template<class T>inline void rd(T &x)
{
    cp=gc();x=0;int f=0;
    for(;!isdigit(cp);cp=gc()) if(cp=='-') f=1;
    for(;isdigit(cp);cp=gc()) x=x*10+(cp^48);
    if(f) x=-x;
}

inline void prit(int x)
{
    if(x<0) putchar('-'),x=-x;
    if(x>9) prit(x/10);putchar('0'+(x%10));
}

inline int fd(int x){return lower_bound(v+1,v+num,x)-v;}

int cot,exi[N];
multiset<int>t[N];
multiset<int>::iterator it,it1,it2;
namespace SGT{
    
#define lc k<<1
#define rc k<<1|1
#define mid ((l+r)>>1)
#define lcc lc,l,mid
#define rcc rc,mid+1,r
int n,mn[N<<2],mxv[N<<2],X,Y,Z;

struct Hp{
    priority_queue<int,vector<int>,greater<int> >a,b;
    inline void push(int x){a.push(x);}
    inline void del(int x){b.push(x);}
    inline int top(){
        for(;(!b.empty()) && a.top()==b.top();a.pop(),b.pop());
        return a.top(); 
    }
}q[N];

void build(int k,int l,int r)
{
    mn[k]=MX;
    if(l==r) {mxv[k]=v[l];if(l==n) mn[k]=-MX;return;}
    build(lcc);build(rcc);
    mxv[k]=max(mxv[lc],mxv[rc]);mn[k]=min(mn[lc],mn[rc]);
}

inline void init(int n_)
{
    n=n_;build(1,1,n);int i;
    for(i=1;i<n;++i) q[i].push(MX);
    for(i=1;i<=K;++i) q[n].push(-MX);//每种颜色都有一个前驱 
}

void oo(int k,int l,int r,int op)
{
    if(l==r){ 
        if(op==0) q[l].del(Y);
        else if(op==1) q[l].push(Y);
        else q[l].del(Y),q[l].push(Z);
        mn[k]=q[l].top();
        return;
    }
    if(X<=mid) oo(lcc,op);else oo(rcc,op);
    mn[k]=min(mn[lc],mn[rc]);
}

inline void add(int tp,int x)
{
    exi[tp]++;if(exi[tp]==1) cot++;
    it1=t[tp].insert(x);it2=it1;
    --it1;++it2;
    X=fd(x);Y=(*it1);oo(1,1,n,1);
    X=fd(*it2);Y=(*it1);Z=x;oo(1,1,n,2);
}

inline void del(int tp,int x)
{
    exi[tp]--;if(exi[tp]==0) cot--;
    it=t[tp].find(x);it1=it;it2=it1;
    --it1;++it2;
    X=fd(x);Y=(*it1);oo(1,1,n,0);
    X=fd(*it2);Y=x;Z=(*it1);oo(1,1,n,2);
    t[tp].erase(it);
}

int ask(int k,int l,int r,int x,int &dr)
{
    if(cot!=K) return -1;
    if(l==r) {return min((x<<1)-min(dr,mn[k]),mxv[k])-x;}
    if(x>mxv[lc]) return ask(rcc,x,dr);//x->non-LSH compared with mxv[lc] NOT mid
    if(mxv[lc]+1+min(mn[rc],dr)<=(x<<1)) return ask(rcc,x,dr);
    dr=min(mn[rc],dr);
    return ask(lcc,x,dr);
}

}

int main(){
    int i,j,x,y,c,d;
    rd(n);rd(K);rd(m);
    for(i=1;i<=n;++i){
    	rd(x);rd(y);rd(c);rd(d);v[i]=x;
    	a[++cnt]=(qr){x,y,c,-1};
    	a[++cnt]=(qr){x,y,d+1,-2};
    }
    sort(v+1,v+n+1);num=unique(v+1,v+n+1)-v-1;
    v[++num]=MX<<1;//以防query中x>v[n] MX<<1-> min((x<<1)-min(dr,mn[k]),mxv[k]) 保证取min的是左侧 
    SGT::init(num);
    for(i=1;i<=m;++i){
        rd(x);rd(y);
        a[++cnt]=(qr){x,0,y,i};
    }
    for(i=1;i<=K;++i) t[i].insert(MX),t[i].insert(-MX);
    sort(a+1,a+cnt+1);
    for(i=1;i<=cnt;++i){
        if(a[i].op>0) ans[a[i].op]=SGT::ask(1,1,num,a[i].pos,(as=MX));
        else if(a[i].op==-1) SGT::add(a[i].typ,a[i].pos);
        else SGT::del(a[i].typ,a[i].pos);
    }
    for(i=1;i<=m;++i) {prit(ans[i]);if(i<m) putchar('\n');}		
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值