CodeForces 1000F One Occurrence (线段树+离线/主席树)*

题目链接:http://codeforces.com/problemset/problem/1000/F

题目大意

给定一个序列和若干个查询,
每次查询区间中只出现一次的那个数字,
若答案有若干个则输出任意一个,
否则输出零。

题目分析 

根据贪心的思想,对于一个特定的区间,
假设每个位置都有一个pre,即上一次出现该位置数的位置,
如果第一次出现明显位置应该为0,
一个区间中是否存在答案,就是看这个区间的pre最小值,是否
大于左端点,那么我们只要看其区间最小值即可,注意要存个二元组,,因为
如果pre值为0则无法确定位置数,一种常规方法是线段树离线,
因为在线的话不确定查询区间出现的时间顺序,
那么当前维护的线段树不会对以前的区间产生贡献,
离线可以解决这个问题,按右端点排序,直接往线段树按序更新值即可,
那么既然涉及到时间顺序的影响问题,主席树也是一个手段。
主席树就是暴力空间般把时间序都存储下来了,
但是一个时间刻只影响一条链所有空间不会特别大,
既然我们对每个扫描时间(总共n)都开线段树存储时间刻了,
那么对于这个时间线段树,当前位置的pre影响应该消去,
所以空间要开四倍左右,然后更新i位置用位置上的pre值即可。
最后直接在第r个树上区间查询找最小的即可。
时间复杂度:O(n+qlogn).

#include<bits/stdc++.h>
using namespace std;

#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long

#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=5e5+5;
const int maxm=2e7+5;
const int ub=1e6;
const int INF=1e9;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:
给定一个序列和若干个查询,
每次查询区间中只出现一次的那个数字,
若答案有若干个则输出任意一个,
否则输出零。

题目分析:
根据贪心的思想,对于一个特定的区间,
假设每个位置都有一个pre,即上一次出现该位置数的位置,
如果第一次出现明显位置应该为0,
一个区间中是否存在答案,就是看这个区间的pre最小值,是否
大于左端点,那么我们只要看其区间最小值即可,注意要存个二元组,,因为
如果pre值为0则无法确定位置数,一种常规方法是线段树离线,
因为在线的话不确定查询区间出现的时间顺序,
那么当前维护的线段树不会对以前的区间产生贡献,
离线可以解决这个问题,按右端点排序,直接往线段树按序更新值即可,
那么既然涉及到时间顺序的影响问题,主席树也是一个手段。
主席树就是暴力空间般把时间序都存储下来了,
但是一个时间刻只影响一条链所有空间不会特别大,
既然我们对每个扫描时间(总共n)都开线段树存储时间刻了,
那么对于这个时间线段树,当前位置的pre影响应该消去,
所以空间要开四倍左右,然后更新i位置用位置上的pre值即可。
最后直接在第r个树上区间查询找最小的即可。
时间复杂度:O(n+qlogn).
*/
int rt[maxn],ls[maxm],rs[maxm];
struct node{ int pos , val; };
node sum[maxm];
int tot=0;
void build(int& o,int l,int r){
    o=++tot;
    sum[o].val=INF;
    if(l==r) return;
    int mid=l+r>>1;
    build(ls[o],l,mid);
    build(rs[o],mid+1,r);
}
void update(int& o,int l,int r,int last,int p,int v){
    o=++tot;
    ls[o]=ls[last],rs[o]=rs[last];
    if(l==r){
        sum[o].val=v;
        sum[o].pos=l;
        return;
    }
    int mid=l+r>>1;
    if(p<=mid) update(ls[o],l,mid,ls[o],p,v);
    else update(rs[o],mid+1,r,rs[o],p,v);
    if(sum[ls[o]].val<sum[rs[o]].val) sum[o]=sum[ls[o]];
    else sum[o]=sum[rs[o]];
}
node query(int o,int l,int r,int pl,int pr){
    if(pl<=l&&r<=pr) return sum[o];
    if(sum[o].val==INF) return sum[o];
    int mid=l+r>>1;
    node tp1,tp2;
    tp2.val=INF;
    if(pl<=mid){
        tp1=query(ls[o],l,mid,pl,pr);
        if(tp1.val<tp2.val) tp2=tp1;
    }
    if(mid<pr){
        tp1=query(rs[o],mid+1,r,pl,pr);
        if(tp1.val<tp2.val) tp2=tp1;
    }
    return tp2;
}
int a[maxn],n,x,y,q;
int pre[maxn],last[maxn];
int main(){
    scanf("%d",&n);
    build(rt[0],1,n);
    rep(i,1,n+1) scanf("%d",&a[i]);
    rep(i,1,n+1){
        if(last[a[i]]) pre[i]=last[a[i]];
        last[a[i]]=i;
    }
    rep(i,1,n+1){
        if(pre[i]){
            int tmp;
            update(tmp,1,n,rt[i-1],pre[i],INF);
            update(rt[i],1,n,tmp,i,pre[i]);
        }
        else update(rt[i],1,n,rt[i-1],i,0);
    }
    scanf("%d",&q);
    rep(i,0,q){
        scanf("%d%d",&x,&y);
        node ret=query(rt[y],1,n,x,y);
        if(ret.val>=x) puts("0");
        else printf("%d\n",a[ret.pos]);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37451344/article/details/88661504