bzoj 3524 可持久化线段树

  我们可以先离散化,然后建立权值的可持久化线段树,记录每个数出现的次数,对于区间询问直接判断左右儿子的cnt是不是大于(r-k+1)/2,然后递归到最后一层要是还是大于就有,否则不存在。

  反思:挺简单一道题调了一个晚上加一个几节课= =,原因是这道题的空间给的是128MB,那么就会有比较严重的卡空间的地方,开始我的线段树是记录的左右儿子和代表的区间,这样会MLE,那么我们可以不记录代表的区间然后递归的时候传上去区间也可以起到同样的效果。

/**************************************************************

    Problem: 3524

    User: BLADEVIL

    Language: C++

    Result: Accepted

    Time:7392 ms

    Memory:125808 kb

****************************************************************/

 

//By BLADEVIL

#include <cstdio>

#include <cstring>

#include <algorithm>

#define maxn 500010

 

using namespace std;

 

struct segment {

    int cnt;

    int son[2];

    segment() {

        cnt=0;

        memset(son,0,sizeof son);

    }

}t[10000000];

 

struct rec {

    int num,key;

}a[maxn];

 

int n,m,tot;

int rot[maxn],ans[maxn];

 

bool cmp1(rec x,rec y) {

    return x.key<y.key;

}

 

bool cmp2(rec x,rec y) {

    return x.num<y.num;

}

 

void build(int &x,int l,int r) {

    if (!x) x=++tot;

    if (l==r) return ;

    int mid=l+r>>1;

    build(t[x].son[0],l,mid); build(t[x].son[1],mid+1,r);

    return ;

}

 

void insert(int &x,int rot,int key,int l,int r) {

    if (!x) x=++tot;

    if (l==r) {

        t[x].cnt=t[rot].cnt+1; return ;

    }

    int mid=l+r>>1;

    if (key>mid) {

        t[x].son[0]=t[rot].son[0];

        insert(t[x].son[1],t[rot].son[1],key,mid+1,r);

    } else {

        t[x].son[1]=t[rot].son[1];

        insert(t[x].son[0],t[rot].son[0],key,l,mid);

    }

    t[x].cnt=t[rot].cnt+1;

    return ;

}

 

int query(int lx,int rx,int key,int l,int r) {

    //printf("%d %d %d\n",lx,rx,key);

    if (l==r) return l;

    int mid=l+r>>1;

    if (t[t[rx].son[0]].cnt-t[t[lx].son[0]].cnt>key) return query(t[lx].son[0],t[rx].son[0],key,l,mid); else

    if (t[t[rx].son[1]].cnt-t[t[lx].son[1]].cnt>key) return query(t[lx].son[1],t[rx].son[1],key,mid+1,r); else

        return 0;

}

 

int main() {

    //freopen("kur.in","r",stdin); freopen("kur.out","w",stdout);

    scanf("%d%d",&n,&m);

    for (int i=1;i<=n;i++) scanf("%d",&a[i].key),a[i].num=i;

    sort(a+1,a+1+n,cmp1);

    int j=1; ans[1]=a[1].key;

    for (int i=1,cur=a[1].key;i<=n;i++)

        if (a[i].key==cur) a[i].key=j; else cur=a[i].key,a[i].key=++j,ans[j]=cur;

    //for (int i=1;i<=n;i++) printf("%d %d\n",a[i].num,a[i].key);

    sort(a+1,a+1+n,cmp2);

    build(rot[0],1,j);

    for (int i=1;i<=n;i++) insert(rot[i],rot[i-1],a[i].key,1,j);

    //for (int i=1;i<=tot;i++) printf("%d %d %d %d %d %d\n",i,t[i].left,t[i].right,t[i].son[0],t[i].son[1],t[i].cnt);

    while (m--) {

        int l,r; scanf("%d%d",&l,&r);

        if (l>r) swap(l,r);

        printf("%d\n",ans[query(rot[l-1],rot[r],(r-l+1)/2,1,j)]);

    }

    //fclose(stdin); fclose(stdout);

    return 0;

}

学长给了一个随机算法,虽然参数改了不是T就是WA,还是觉得挺有纪念意义的= =。

//By BLADEVIL

#include <ctime>

#include <cstdio>

#include <vector>

#include <cstdlib>

#define maxn 500010

#define k 10



using namespace std;



int n,m;

int a[maxn];

vector<int>rot[maxn];



int calc(int x,int y) {

    int l=0,r=rot[x].size()-1;

    int ans=0;

    while (l<=r) {

        int mid=l+r>>1;

        //printf("%d %d %d\n",l,r,mid);

        if (rot[x][mid]<=y) ans=mid,l=mid+1; else r=mid-1;

    }

    return ans;

}



int judge(int x,int l,int r) {

    int a1=calc(x,l),a2=calc(x,r);

    int ans=a2-a1+1;

    if (rot[x][a1]!=l) ans--;

    return ans;

}



int main() {

    //freopen("kur.in","r",stdin); freopen("kur.out","w",stdout);

    srand((int)time(NULL));

    /*

    scanf("%d",&n);

    for (int i=1;i<=n;i++) scanf("%d",&a[i]);

    for (int i=1;i<=n;i++) rot[1].push_back(a[i]);

    scanf("%d",&m);

    printf("%d\n",calc(1,m));

    return 0;

    */

    scanf("%d%d",&n,&m); 

    for (int i=1;i<=n;i++) scanf("%d",&a[i]);

    for (int i=1;i<=n;i++) rot[a[i]].push_back(i);

    while (m--) {

        int l,r; scanf("%d%d",&l,&r);

        for (int i=1;i<=k;i++) {

            int cur=l+rand()%(r-l+1);

            if (judge(a[cur],l,r)>(r-l+1)/2) {

                printf("%d\n",a[cur]); l=r=-1;

                break;

            }

        }

        if (l!=-1) printf("0\n");

    }

    fclose(stdin); fclose(stdout);

    return 0;

}

 

你可能感兴趣的:(线段树)