One Occurrence [CodeForces1000F]

题目传送门

这个题目有多种写法

1.线段树动态更新与查找
pos[i]记录位置i上出现的数上次出现的位置。将询问按右区间排序。

从1到n扫,把线段树上pos[i]的值改成INF,
比如 1 1 ,线段树原来是 0 1 ,扫完第二个 1 后,线段树变成 INF 1,那么查找的时候,查找 L到 R之内最小的那个值,注意最后还要判断这个最小值是不是比L还要小。

code:


#include <bits/stdc++.h>

using namespace std;

#define File(x) freopen("(x)","r",stdin)
#define pf printf
#define ull unsigned long long
#define db double
#define ll long long
const int  MAXN=5e5+10;
#define MAXM 
#define P 

int T, n, m, l, r, siz, lim, bol[MAXN], ans[MAXN], t[MAXN], a[MAXN],as;

struct Q {int l, r, x, y, id;} q[MAXN]; 
 

bool CMP(Q x, Q y)
{
     return x.r<y.r;  
}

int pos[MAXN],la[MAXN],lw[MAXN],pr[MAXN],mn[MAXN<<2],num[MAXN<<2];

void build(int u,int L,int R,int ps){
    if(L==R){ 
        mn[u]=pos[ps];
        return;
    }
    int lson=u<<1,rson=u<<1|1,mid=L+R>>1;
    if(ps<=mid)
    build(lson,L,mid,ps);
    else
    build(rson,mid+1,R,ps);
    mn[u]=min(mn[lson],mn[rson]);
}

void upd(int u,int L,int R,int ps){ 
    if(L==R){
        mn[u]=MAXN+10000;return;
    }
    int lson=u<<1,rson=u<<1|1,mid=L+R>>1;
    if(ps<=mid)
    upd(lson,L,mid,ps);
    else
    upd(rson,mid+1,R,ps);
    mn[u]=min(mn[lson],mn[rson]);
}

int Q(int u,int L,int R,int l,int r){
    int lson=u<<1,rson=u<<1|1,mid=L+R>>1;
    int w1=0,w2=0;
    if(mn[u]>=MAXN)return 0;


  //  cout<<"Q"<<l<<" "<<r<<" "<<L<<" "<<R<<endl;
   // cout<<mn[lson]<<"&"<<mn[rson]<<" "<<mn[u]<<endl;

    if(L==R)return mn[u]<MAXN+1?a[L]:0;
    
    if(mn[rson]<l&&r>mid)
         if(w2=Q(rson,mid+1,R,l,r))return w2;
    if(mn[lson]<l&&l<=mid){
        if(w1=Q(lson,L,mid,l,r))return w1;  
    }
    return 0;
}

int main()
{ 
        cin>>n; 
        
        for(int i=0;i<(MAXN<<2);i++)mn[i]=MAXN+100000;

        for(int i=1; i<=n; ++i) {
            scanf("%d", &a[i]); 
        }
         for(int i=1; i<=n; ++i) { 
            pos[i]=la[a[i]];
            la[a[i]]=i;
        }
        
        cin>>m;
        
        for(int i=1; i<=m; ++i) {
            scanf("%d%d", &q[i].l,&q[i].r); 
            q[i].id=i;
        }
        sort(q+1, q+m+1, CMP); 
        int ps=0;
        for(int i=1; i<=m; ++i) {  
            while(ps<q[i].r){
                ++ps;
                build(1,1,n,ps);  
                if(pos[ps]>0){ 
                    upd(1,1,n,pos[ps]);  
                }   
            }
            ans[q[i].id]=Q(1,1,n,q[i].l,q[i].r);
        }
        for(int i=1; i<=m; ++i) printf("%d
", ans[i]); 
}

2.莫队

注意数据集合的增和删。用一个stack,增就直接入栈,删就把栈顶放到这个数原来的位置。(可以记录每个数在栈位置).注意这份代码会T。
T——T

#include <bits/stdc++.h>

using namespace std;

#define File(x) freopen("(x)","r",stdin)
#define pf printf
#define ull unsigned long long
#define db double
#define ll long long
const int  MAXN=5e5+10;
#define MAXM 
#define P 

int T, n, m, l, r, siz, lim, bol[MAXN], ans[MAXN], t[MAXN], num[MAXN], a[MAXN],as;
struct Q {int l, r, x, y, id;} q[MAXN]; 
 int stk[MAXN],top=0,pos[MAXN];
void add(int x, int k)
{
   // cout<<x<<"-"<<k<<endl;
    if(k==1)stk[++top]=x,pos[x]=top;
    else{
        pos[stk[top]]=pos[x];
        stk[pos[x]]=stk[top];
        --top;
    }
}
 

bool CMP(Q x, Q y)
{
    if(bol[x.l]==bol[y.l]) {
        if(bol[x.l]&1) return x.r<y.r;
        else return x.r>y.r;
    }
    return x.l<y.l;
}

int main()
{ 
        cin>>n;
        l=1, r=0, lim=0, siz=max(1, (int)sqrt(n)); 
        for(int i=1; i<=5e5+5; ++i) num[i]=t[i]=0;
        for(int i=1; i<=n; ++i) {
            scanf("%d", &a[i]); 
            bol[i]=(i-1)/siz+1;
        }

        cin>>m;
        
        for(int i=1; i<=m; ++i) {
            scanf("%d%d", &q[i].l,&q[i].r); 
            q[i].id=i;
        }

        sort(q+1, q+m+1, CMP);
        
        for(int i=1; i<=m; ++i) {  
            while(r<q[i].r) {//jiaru
                r++;
                if(!num[a[r]]) add(a[r], 1);
                else {
                    if(num[a[r]]==1)
                    add(a[r],-1);
                }
                num[a[r]]++;
            }
            while(r>q[i].r) {//tichu
                num[a[r]]--;
                if(num[a[r]]==1) add(a[r], 1);
                else if(num[a[r]]==0)add(a[r],-1);
                r--;
            }
            while(l<q[i].l) {//tichu 
                num[a[l]]--; 
                if(!num[a[l]]) add(a[l], -1);
                if(num[a[l]]==1)add(a[l],1);
                l++;
            }
            while(l>q[i].l) {//jiaru
                l--;
                if(!num[a[l]]) add(a[l], 1);
                else if(num[a[l]]==1)add(a[l],-1);
                num[a[l]]++;
            }  
            ans[q[i].id]=stk[top];
        }
        for(int i=1; i<=m; ++i) printf("%d
", ans[i]); 
}

原文地址:https://www.cnblogs.com/GUOGaby/p/15050205.html