BZOJ5462 APIO2018新家(线段树+堆)

  一个显然的做法是二分答案后转化为查询区间颜色数,可持久化线段树记录每个位置上一个同色位置,离线后set+树状数组套线段树维护。这样是三个log的。

  注意到我们要知道的其实只是是否所有颜色都在该区间出现,可以改为查询后缀区间的上一个同色位置中最小的。这样我们就只需要set+线段树就可以维护了,同样二分答案是两个log。直接在线段树上二分就变成了一个log。

  给每种颜色在坐标-inf和inf处加点来避免乱七八糟的讨论。离散化一下。对于相同坐标的点,在叶子维护堆即可。调过样例就能1A了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
using namespace std;
#define ll long long
#define N 600010
#define inf 600000003
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,m,q,t,L[N<<2],R[N<<2],tree[N<<2],ans[N],u[N];
struct data
{
    int x,t,op;int p,i;
    bool operator <(const data&a) const
    {
        return t<a.t||t==a.t&&abs(op)>abs(a.op);
    }
}a[N<<2];
priority_queue<int,vector<int>,greater<int> > ins[N<<2],del[N<<2];
multiset<int> color[N];
void build(int k,int l,int r)
{
    L[k]=l,R[k]=r;tree[k]=inf;
    if (l==r) return;
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
}
int query(int k,int l,int r,int x,int last)
{
    if (L[k]==R[k]) return max(u[L[k]]-x,x-last);
    int mid=L[k]+R[k]>>1;
    if (r<=mid) return query(k<<1,l,r,x,min(tree[k<<1|1],last));
    else if (l>mid) return query(k<<1|1,l,r,x,last);
    else
    {
        if (u[mid]-x>x-min(last,tree[k<<1|1])) return query(k<<1,l,mid,x,min(last,tree[k<<1|1]));
        else return min(x-min(last,tree[k<<1|1]),query(k<<1|1,mid+1,r,x,last));
    }
}
void modify(int k,int p,int x,int op)
{
    if (L[k]==R[k])
    {
        if (op==1) ins[k].push(x);else del[k].push(x);
        while (!del[k].empty()&&ins[k].top()==del[k].top()) ins[k].pop(),del[k].pop();
        tree[k]=ins[k].empty()?inf:ins[k].top();
        return;
    }
    int mid=L[k]+R[k]>>1;
    if (p<=mid) modify(k<<1,p,x,op);
    else modify(k<<1|1,p,x,op);
    tree[k]=min(tree[k<<1],tree[k<<1|1]);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj5462.in","r",stdin);
    freopen("bzoj5462.out","w",stdout);
    const char LL[]="%I64d
";
#else
    const char LL[]="%lld
";
#endif
    n=read(),m=read(),q=read();
    for (int i=1;i<=n;i++)
    {
        int x=read(),y=read(),l=read(),r=read();
        t++;a[t].x=x,a[t].t=l,a[t].op=1,a[t].p=y;
        t++;a[t].x=x,a[t].t=r+1,a[t].op=-1,a[t].p=y;
        u[i]=x;
    }
    for (int i=1;i<=q;i++) t++,a[t].x=read(),a[t].t=read(),a[t].op=0,a[t].p=0,a[t].i=i,u[n+i]=a[t].x;
    sort(u+1,u+n+q+1);int v=unique(u+1,u+n+q+1)-u-1;u[0]=-inf,u[++v]=inf;
    for (int i=1;i<=t;i++) a[i].x=lower_bound(u,u+v+1,a[i].x)-u;
    build(1,0,v);
    sort(a+1,a+t+1);
    //for (int i=1;i<=t;i++) cout<<a[i].x<<' '<<a[i].t<<' '<<a[i].op<<' '<<a[i].p<<' '<<a[i].i<<endl;
    for (int i=1;i<=m;i++)
    {
        color[i].insert(0),color[i].insert(v);
        modify(1,v,-inf,1);
    }
    for (int i=1;i<=t;i++)
    if (a[i].op==0) ans[a[i].i]=query(1,a[i].x,v,u[a[i].x],inf);
    else if (a[i].op==-1)
    {
        multiset<int>::iterator it=color[a[i].p].find(a[i].x);
        it++;int x=*it;
        it--,it--;int y=*it;
        it++;color[a[i].p].erase(it);
        modify(1,x,u[a[i].x],-1),modify(1,a[i].x,u[y],-1),modify(1,x,u[y],1);
    }
    else
    {
        multiset<int>::iterator it=color[a[i].p].lower_bound(a[i].x);
        int x=*it;
        it--;int y=*it;
        color[a[i].p].insert(a[i].x);
        modify(1,x,u[a[i].x],1),modify(1,a[i].x,u[y],1),modify(1,x,u[y],-1);
    }
    for (int i=1;i<=q;i++) printf("%d
",ans[i]>inf/3?-1:ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/Gloid/p/10140787.html