VK Cup 2015 - Qualification Round 1 D. Closest Equals (主席树)

题目链接

题面:
在这里插入图片描述

题意:
给定一个数组 ai,有m个询问,每个询问给定 l ,r 去区间 [ l , r ] 中相同的数字的最近距离。

题解:
考虑主席树。
当前是第 i 个数据,即 a [ i ] , 设 p [ a [ i ] ] 是 a [ i ] 之前离 a [ i ] 最近的相同的数的位置。
那么在第 i 棵树上的 p [ a [ i ] ] 位置 更新最小值为 a [ i ] - p [ a [ i ] ]
考虑查询 l ,r
我们在第 r 棵树上查询 l 以后的最小值。
因为本身就需要一个log的复杂度,那么就不离散化了,直接用map标记前一个数的位置。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<unordered_map>
#include<set>
#define ui unsigned int
#define ll long long
#define llu unsigned ll
#define ld long double
#define pr make_pair
#define pb push_back
#define lc (cnt<<1)
#define rc (cnt<<1|1)
#define len(x)  (t[(x)].r-t[(x)].l+1)
#define tmid ((l+r)>>1)
#define forhead(x) for(int i=head[(x)];i;i=nt[i])
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define one(n) for(int i=1;i<=(n);i++)
#define rone(n) for(int i=(n);i>=1;i--)
#define fone(i,x,n) for(int i=(x);i<=(n);i++)
#define frone(i,n,x) for(int i=(n);i>=(x);i--)
#define fonk(i,x,n,k) for(int i=(x);i<=(n);i+=(k))
#define fronk(i,n,x,k) for(int i=(n);i>=(x);i-=(k))
#define two(n,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
#define ftwo(i,n,j,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
#define cls(a) memset(a,0,sizeof(a))
#define cls1(a) memset(a,-1,sizeof(a))
#define clsmax(a) memset(a,0x3f,sizeof(a))
#define clsmin(a) memset(a,0x80,sizeof(a))
#define cln(a,num) memset(a,0,sizeof(a[0])*num)
#define cln1(a,num) memset(a,-1,sizeof(a[0])*num)
#define clnmax(a,num) memset(a,0x3f,sizeof(a[0])*num)
#define clnmin(a,num) memset(a,0x80,sizeof(a[0])*num)
#define sc(x) scanf("%d",&x)
#define sc2(x,y) scanf("%d%d",&x,&y)
#define sc3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define scl(x) scanf("%lld",&x)
#define scl2(x,y) scanf("%lld%lld",&x,&y)
#define scl3(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)
#define scf(x) scanf("%lf",&x)
#define scf2(x,y) scanf("%lf%lf",&x,&y)
#define scf3(x,y,z) scanf("%lf%lf%lf",&x,&y,&z)
#define scs(x) scanf("%s",x+1)
#define scs0(x) scanf("%s",x)
#define scline(x) scanf("%[^\n]%*c",x+1)
#define scline0(x) scanf("%[^\n]%*c",x)
#define pcc(x) putchar(x)
#define pc(x) printf("%d\n",x)
#define pc2(x,y) printf("%d %d\n",x,y)
#define pc3(x,y,z) printf("%d %d %d\n",x,y,z)
#define pck(x) printf("%d ",x)
#define pcl(x) printf("%lld\n",x)
#define pcl2(x,y) printf("%lld %lld\n",x,y)
#define pcl3(x,y,z) printf("%lld %lld %d\n",x,y,z)
#define pclk(x) printf("%lld ",x)
#define pcf2(x) printf("%.2f\n",x)
#define pcf6(x) printf("%.6f\n",x)
#define pcf8(x) printf("%.8f\n",x)
#define pcs(x) printf("%s\n",x+1)
#define pcs0(x) printf("%s\n",x)
#define pcline(x) for(int i=1;i<=15;i++) pcc(x);pcc('\n')
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1.0);
const int maxm=100100;
const int up=100000;
const int hp=13331;
const int maxn=500100;

struct node
{
    int cl,cr;
    int minn;
}t[maxn*22];

int a[maxn],rt[maxn],cnt=0;

map<int,int>mp;

void init(void)
{
    t[0].minn=inf;
}

int change(int now,int pos,int val,int l,int r)
{
    int p=++cnt;
    t[p]=t[now];
    t[p].minn=min(t[p].minn,val);
    if(l==r) return p;
    if(pos<=tmid) t[p].cl=change(t[now].cl,pos,val,l,tmid);
    else t[p].cr=change(t[now].cr,pos,val,tmid+1,r);
    return p;
}

int ask(int p,int pos,int l,int r)
{
    if(l==r) return t[p].minn;
    int al=inf,ar=inf;
    if(pos<=tmid) al=ask(t[p].cl,pos,l,tmid),ar=t[t[p].cr].minn;
    else ar=ask(t[p].cr,pos,tmid+1,r);
    return min(al,ar);//min被宏定义掉了,直接取min会出问题(有可能会多次调用ask)
}


int main(void)
{
    init();
    int n,m;
    sc2(n,m);
    one(n)
    {
        sc(a[i]);
        rt[i]=rt[i-1];
        if(mp.count(a[i]))
            rt[i]=change(rt[i-1],mp[a[i]],i-mp[a[i]],1,n);
        mp[a[i]]=i;
    }
    int l,r;
    one(m)
    {
        sc2(l,r);
        int now=ask(rt[r],l,1,n);
        pc(now==inf?-1:now);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值