码迷,mamicode.com
首页 > 其他好文 > 详细

dtoi3733 New Home

时间:2020-02-02 01:26:01      阅读:72      评论:0      收藏:0      [点我收藏+]

标签:const   print   指定   pst   题解   htm   旅行   getch   现在   

题意:

     五福街是一条笔直的道路,这条道路可以看成一个数轴,街上每个建筑物的坐标都可以用一个整数来表示。小明是一位时光旅行者,他知道在这条街上,在过去现在和未来共有 n个商店出现。第 i个商店可以使用四个整数 xi?,ti?,ai?,bi?描述,它们分别表示:商店的坐标、商店的类型、商店开业的年份、商店关闭的年份。

小明希望通过时光旅行,选择一个合适的时间,住在五福街上的某个地方。他给出了一份他可能选择的列表,上面包括了 q个询问,每个询问用二元组 (坐标,时间)表示。第 i对二元组用两个整数 li?,yi?描述,分别表示选择的地点 li?和年份 yi?

现在,他想计算出在这些时间和地点居住的生活质量。他定义居住的不方便指数为:在居住的年份,离居住点最远的商店类型到居住点的距离。类型 t的商店到居住点的距离定义为:在指定的年份,类型 t的所有营业的商店中,到居住点距离最近的一家到居住点的距离。我们说编号为 i的商店在第 y年在营业当且仅当 ai?ybi? 。注意,在某些年份中,可能在五福街上并非所有 k种类型的商店都有至少一家在营业。在这种情况下,不方便指数定义为 -1

你的任务是帮助小明求出每对(坐标,时间)二元组居住的不方便指数。

题解:

     先将询问按照时间排序,离线来做。

     这样我们按时间顺序插入/删除商店,对于一个询问,我们首先可以二分答案,接下来问题变成了求一段区间中有多少种不同的元素。那么这里有一个做法,就是将每一个点的权值设为nex[i],nex[i]表示下一个跟当前商店类型相同的商店的位置,然后插入线段树中,查询l,r中有多少nex[i]大于r。这可以树套树解决,但是分析复杂度,发现有3个log,显然是不可能过的。

     再分析一下问题的性质,我们发现并不需要求有多少种不同的元素,只需要求有没有所有的元素即可。我们可以转变思路,只需要判断[0,l-1]中所有nex[i]的最大值是否小于等于r即可。这里有个边界,我们假定所有类型的商店每时每刻在0和Max+1的位置都分别开设着。这样我们就可以在两个log的时间内解决这道题,使用线段树维护即可。

     但是本题有一个非常繁琐的东西,就是重复元素。我们需要用multiset在线段树的叶子中记录下元素用于删除插入,还要考虑新商店开设的位置重复的问题等等,所以也需要multiset维护。导致了常数的巨大无比,卡了好久才过。

#include<cstdio>
#include<set>
#include<vector>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int INF=1e8;
int n,k,m,ans[300002],cnt=1;
typedef struct{
    int Max,ls,rs;
    multiset<int>a;
}P;
typedef struct{
    int x,t,a,b;
}PP;
typedef struct{
    bool u;
    int x,t;
}PPP;
typedef struct{
    int x,tim,num;
}PPPP;
bool cmp(PPPP aa,PPPP bb){
    return (aa.tim<bb.tim);
}
P p[10000002];
PP d[300002];
multiset<int>q[300002];
vector<PPP>g[300002];
PPPP h[300002];
int lb(int z,int lef,int righ){
    int mid;
    while(lef<righ)
    {
        mid=(lef+righ)/2;
        if (h[mid].tim>=z)righ=mid;else lef=mid+1;
    }
    return lef;
}
int ub(int z,int lef,int righ){
    int mid;
    while(lef<righ)
    {
        mid=(lef+righ)/2;
        if (h[mid].tim<=z)lef=mid+1;else righ=mid;
    }
    return lef;
}
void gengxin(int root,int begin,int end,int wz,int z,int th,bool u){
    if (begin==end)
    {
        if (!u)
        {
            multiset<int>::iterator it;it=p[root].a.find(z);
            p[root].a.erase(it);
            if (th!=-1)p[root].a.insert(th);
        }
        else p[root].a.insert(z);
        if (p[root].a.empty())p[root].Max=0;
        else
        {
            multiset<int>::iterator it=p[root].a.end();it--;
            p[root].Max=*it;
        }
        return;
    }
    int mid=(begin+end)/2;
    if (wz<=mid)
    {
        if (!p[root].ls)p[root].ls=++cnt;
        gengxin(p[root].ls,begin,mid,wz,z,th,u);
    }
    else
    {
        if (!p[root].rs)p[root].rs=++cnt;
        gengxin(p[root].rs,mid+1,end,wz,z,th,u);
    }
    p[root].Max=max(p[p[root].ls].Max,p[p[root].rs].Max);
}
int chaxun(int root,int begin,int end,int begin2,int end2){
    if (!root || begin>end2 || end<begin2)return 0;
    if (begin>=begin2 && end<=end2)return p[root].Max;
    int mid=(begin+end)/2;
    return max(chaxun(p[root].ls,begin,mid,begin2,end2),chaxun(p[root].rs,mid+1,end,begin2,end2));
}
int read(){
    int f=0;char ch=getchar();
    while(ch<0 || ch>9)ch=getchar();
    while(ch>=0 && ch<=9){f=f*10+ch-48;ch=getchar();}
    return f;
}
int main()
{
    n=read();k=read();m=read();
    for (int i=1;i<=n;i++)
    {
        d[i].x=read();d[i].t=read();d[i].a=read();d[i].b=read();
    }
    for (int i=1;i<=m;i++)
    {
        h[i].x=read();h[i].tim=read();h[i].num=i;
    }
    sort(h+1,h+m+1,cmp);
    for (int i=1;i<=n;i++)
    {
        int l=lb(d[i].a,1,m),r=ub(d[i].b,1,m+1);
        if (l==r)continue;
        PPP aa;aa.u=1;aa.x=d[i].x;aa.t=d[i].t;
        g[l].push_back(aa);
        aa.u=0;
        g[r].push_back(aa);
    }
    for (int i=1;i<=k;i++)
    {
        q[i].insert(0);q[i].insert(INF+1);
        gengxin(1,0,INF+1,0,INF+1,0,1);
    }
    for (int i=1;i<=m;i++)
    {
        for (int j=0;j<g[i].size();j++)
        {
            int tt=g[i][j].t,xx=g[i][j].x;
            if (g[i][j].u)
            {
                multiset<int>::iterator ls,nx;
                nx=ls=q[tt].lower_bound(xx);ls--;
                if (*nx!=xx)
                {
                    gengxin(1,0,INF+1,*ls,*nx,xx,0);
                    gengxin(1,0,INF+1,xx,*nx,0,1);
                }
                q[tt].insert(xx);
            }
            else
            {
                multiset<int>::iterator ls,nx,it;
                it=q[tt].find(xx);
                nx=ls=q[tt].lower_bound(xx);nx++;
                if (*nx!=xx)
                {
                    ls--;
                    gengxin(1,0,INF+1,*ls,xx,*nx,0);
                    gengxin(1,0,INF+1,xx,*nx,-1,0);
                }
                q[tt].erase(it);
            }
        }
        int lef=0,righ=max(h[i].x-1,INF-h[i].x)+1,mid;
        while(lef<righ)
        {
            mid=(lef+righ)/2;
            int l=max(h[i].x-mid,1),r=min(h[i].x+mid,INF);
            if (chaxun(1,0,INF+1,0,l-1)<=r)righ=mid;else lef=mid+1;
        }
        if (lef!=max(h[i].x-1,INF-h[i].x)+1)ans[h[i].num]=lef;else ans[h[i].num]=-1;
    }
    for (int i=1;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}

 

dtoi3733 New Home

标签:const   print   指定   pst   题解   htm   旅行   getch   现在   

原文地址:https://www.cnblogs.com/1124828077ccj/p/12250858.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!