1. 程式人生 > >BZOJ 1878: [SDOI2009]HH的項鏈

BZOJ 1878: [SDOI2009]HH的項鏈

node post spa 樹狀 for 描述 個數 圖片 etc

題目描述

num[i]表示在[l,r]內數字i的個數

當區間變為[l±1,r]或,[l,r±1]的時候,num[i]由0變為1或由1變為0時答案才會變化

技術分享圖片
#include<complex>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=5e4+7;
struct node{
    int l,r,id;
}q[N<<2];
int n,m;
int ans[N<<2],a[N],num[N*20],pos[N];
int qread()
{
    
int x=0; char ch=getchar(); while(ch<0 || ch>9)ch=getchar(); while(ch>=0 && ch<=9){x=x*10+ch-0;ch=getchar();} return x; } bool cmp(const node &a,const node &b) { if(pos[a.l]==pos[b.l])return a.r<b.r; return pos[a.l]<pos[b.l]; } void change(int
&tot,int id,int add) { if(add) { if(!num[a[id]]) tot++; num[a[id]]++; return; } num[a[id]]--; if(!num[a[id]])tot--; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) a[i]=qread(); scanf("%d",&m); for(int
i=1;i<=m;i++) { q[i].l=qread();q[i].r=qread(); q[i].id=i; } int tmp=sqrt(n); for(int i=1;i<=n;i++) pos[i]=(i-1)/tmp+1; sort(q+1,q+m+1,cmp); int l=1,r=0,tot=0; for(int i=1;i<=m;i++) { while(l<q[i].l) change(tot,l++,0); while(l>q[i].l) change(tot,--l,1); while(r<q[i].r) change(tot,++r,1); while(r>q[i].r) change(tot,r--,0); ans[q[i].id]=tot; } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
莫隊

也可以用離線算法+樹狀數組來做這道題

用nxt[i]來記錄與第i個數相同的上一個數的位置

將詢問的區間按左端點進行排序

用一個指針l指向當前區間的左端點,當l向右移動時,第l個數就不在查詢的區間內了,這時就將樹狀數組中nxt[l]位置上的數+1(自己舉個例子就比較好理解了)

技術分享圖片
#include<complex>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=5e4+7;
struct node{
    int l,r,id;
}q[N<<2];
int n,m;
int c[N],nxt[N],pre[N*20],ans[N<<2];
int qread()
{
    int x=0;
    char ch=getchar();
    while(ch<0 || ch>9)ch=getchar();
    while(ch>=0 && ch<=9){x=x*10+ch-0;ch=getchar();}
    return x;
}
inline int Lowbit(int x)
{
    return x&-x;
}
inline int Add(int x,int v)
{
    for(;x<=n;x+=Lowbit(x))
        c[x]+=v;
}
inline int Sum(int x)
{
    int ans=0;
    for(;x;x-=Lowbit(x))
        ans+=c[x];
    return ans;
}
bool cmp(const node &a,const node &b)
{
    return a.l<b.l;
}
int main()
{
    scanf("%d",&n);
    int x;
    for(int i=1;i<=n;i++)
    {
        x=qread();
        nxt[pre[x]]=i;
        if(!pre[x])Add(i,1);
        pre[x]=i;
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        q[i].l=qread();q[i].r=qread();
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp);
    int l=1;
    for(int i=1;i<=m;i++)
    {
        while(l<q[i].l)
        {
            if(nxt[l])
                Add(nxt[l],1);
            l++;
        }
        ans[q[i].id]=Sum(q[i].r)-Sum(q[i].l-1);
    }
    for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}
樹狀數組

BZOJ 1878: [SDOI2009]HH的項鏈