可持久化数据结构

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

 

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\n",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\n",ans);
    
    fclose(stdin);
    fclose(stdout);
}
View Code

 

posted @ 2015-08-17 15:15  Rivendell  阅读(295)  评论(0编辑  收藏  举报