zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",a[cur]); l=r=-1;
                    break;
                }
            }
            if (l!=-1) printf("0
    ");
        }
        fclose(stdin); fclose(stdout);
        return 0;
    }
  • 相关阅读:
    用友U8 | 【出纳管理】添加日记账时,为什么日期选不了之前的日期?
    用友U8 | 【总账】结账时提示:该凭证已被别的用户锁定,请稍候在试...
    用友U8 | 【实施导航】实施导航进度条一直显示没完成
    利用Action方法委托重构switch接口
    关于wcf序列化后的压缩示例
    sql常用的命令
    WebBrowser通过cookie自动登录网站
    SqlServer大数据的分区方案
    WebBrowser 登录windows集成验证的网站
    SQL大批量插入数据的方式(多表关联) .
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3670758.html
Copyright © 2011-2022 走看看