zoukankan      html  css  js  c++  java
  • 可持久化数据结构

    可持久化线段树就类似于主席树,所以先不放题了。

    bzoj3673||3674 可持久化并查集

    思路:用可持久化线段树来维护每个点的fa信息,然后按秩合并(相当于点的高度)查找的时候顺着父亲暴力查找。这里我们可以找到爸爸儿子那一级就可以了,可以省一些时间。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxnode 8000005
    using namespace std;
    int tot=0,fa[maxnode]={0},deep[maxnode]={0},root[200005]={0},ls[maxnode]={0},rs[maxnode]={0},n;
    void build(int &i,int l,int r)
    {
        int mid;
        if (!i) i=++tot;
        if (l==r){fa[i]=l;return;}
        mid=(l+r)/2;
        build(ls[i],l,mid);build(rs[i],mid+1,r);
    }
    int ask(int i,int l,int r,int x)
    {
        if (l==r) return i;
        int mid=(l+r)/2;
        if (x<=mid) return ask(ls[i],l,mid,x);
        else return ask(rs[i],mid+1,r,x);
    }
    int find(int i,int x)
    {
        int j=ask(i,1,n,x);
        if (x==fa[j]) return j;
        return find(i,fa[j]);
    }
    void merge(int i,int &j,int l,int r,int x,int y)
    {
        j=++tot;int mid;
        if (l==r){fa[j]=y;return;}
        ls[j]=ls[i];rs[j]=rs[i];mid=(l+r)/2;
        if (x<=mid) merge(ls[i],ls[j],l,mid,x,y);
        else merge(rs[i],rs[j],mid+1,r,x,y);
    }
    void add(int i,int l,int r,int x)
    {
        if (l==r) {++deep[i];return;}
        int mid=(l+r)/2;
        if (x<=mid) add(ls[i],l,mid,x);
        else add(rs[i],mid+1,r,x);
    }
    int main()
    {
        int m,i,j,a,b,k,p,q,last=0;
        scanf("%d%d",&n,&m);build(root[0],1,n);
        for (i=1;i<=m;++i)
        {
            scanf("%d",&k);
            if (k==1)
            {
                scanf("%d%d",&a,&b);a^=last;b^=last;
                root[i]=root[i-1];
                p=find(root[i],a);q=find(root[i],b);
                if (fa[p]==fa[q]) continue;
                if (deep[p]>deep[q]) swap(p,q);
                merge(root[i-1],root[i],1,n,fa[p],fa[q]);
                if (deep[p]==deep[q]) add(root[i],1,n,fa[q]);
            }
            if (k==2) {scanf("%d",&a);a^=last;root[i]=root[a];}
            if (k==3)
            {
                scanf("%d%d",&a,&b);a^=last;b^=last;
                root[i]=root[i-1];
                p=find(root[i],a);q=find(root[i],b);
                if (fa[p]==fa[q]) last=1;
                else last=0;
                printf("%d
    ",last);
            }
        }
    }
    View Code

    舰队

    题目大意:求出原数列的一个区间,选其中一个值使次大值xor这个值最大。

    思路:建立一个像主席树的一样的trie,然后对于每个位置求出它左右离他最近的各两个,那它是次大值的区间就是(左2,右1]和[左1,右2),求这几个值可以用链表的思想,从小到大删掉元素,相应的更新。对于这些区间就可以在trie上贪心了(从高位开始,尽量取相反位)。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxnode 50005
    #define up 30
    using namespace std;
    struct use{
        int nn,po;
    }ai[maxnode]={0};
    int trie[1600005][3]={0},mx[maxnode][5]={0},next[maxnode]={0},pre[maxnode]={0},num[maxnode][50]={0},
        root[maxnode]={0},tt=0;
    int cmp(const use&x,const use&y){return x.nn==y.nn ? x.po<y.po : x.nn<y.nn;}
    int getnum(int x,int i)
    {
        int j=0;
        while(x){num[i][++j]=x%2;x/=2;}
    }
    void ins(int x,int &y,int w,int k)
    {
        int i,j;
        trie[y=++tt][2]=trie[x][2]+1;
        if (w<=0) return; j=num[k][w];
        ins(trie[x][j],trie[y][j],w-1,k);
        trie[y][j^1]=trie[x][j^1];
    }
    int ask(int l,int r,int w,int k)
    {
        int j;j=num[k][w];
        if (w<=0) return 0;
        if (trie[trie[r][j^1]][2]-trie[trie[l][j^1]][2]>0)
            return ask(trie[l][j^1],trie[r][j^1],w-1,k)|(1<<(w-1));
        else return ask(trie[l][j],trie[r][j],w-1,k);
    }
    int main()
    {
        freopen("collection.in","r",stdin);
        freopen("collection.out","w",stdout);
        
        int n,i,j,ans=0;
        scanf("%d",&n);
        for (i=1;i<=n;++i)
        {
            scanf("%d",&ai[i].nn);
            getnum(ai[i].nn,i);ai[i].po=i;
            next[i]=i+1;pre[i]=i-1;
        }next[0]=1;next[n+1]=n+1;pre[n+1]=n;
        sort(ai+1,ai+n+1,cmp);
        for (i=1;i<=n;++i)
        {
            mx[ai[i].po][0]=pre[pre[ai[i].po]];
            mx[ai[i].po][1]=pre[ai[i].po];
            mx[ai[i].po][2]=next[ai[i].po];
            mx[ai[i].po][3]=next[next[ai[i].po]];
            next[pre[ai[i].po]]=next[ai[i].po];
            pre[next[ai[i].po]]=pre[ai[i].po];
        }
        for (i=1;i<=n;++i) ins(root[i-1],root[i],up,i);
        for (i=1;i<=n;++i)
        {
            if (mx[i][1]) ans=max(ans,ask(root[mx[i][0]],root[mx[i][2]-1],up,i));
            if (mx[i][2]!=n+1) ans=max(ans,ask(root[mx[i][1]],root[mx[i][3]-1],up,i));
        }
        printf("%d
    ",ans);
        
        fclose(stdin);
        fclose(stdout);
    }
    View Code
  • 相关阅读:
    使pre的内容自动换行
    textarea文本换行和页面显示换行符
    SQL查询包含汉字的行
    网站引导页插件intro.js 的用法
    jquery.cookie中的操作
    sql自动生成汉语拼音和首字母函数
    IE,Chrome滚动条样式CSS
    Vcenter server 5.5上传ISO镜像
    Vcenter server 5.5添加用户角色及分配权限
    Vcenter server 5.5安装部署
  • 原文地址:https://www.cnblogs.com/Rivendell/p/4736685.html
Copyright © 2011-2022 走看看