【xsy1629】可持久化序列 - 可持久化平衡树

http://www.cnblogs.com/Sdchr/p/6258827.html

【bzoj4260】REBXOR - Trie

事实上只是一道Trie树的题。

只是被林导钦定成可持久化的了。

区间异或和,转化为前缀异或和。

预处理向前最大的异或和,向后最大的异或和,和前缀最大异或和,枚举分割点求答案。

#include <cstdio>
#include <cctype>
#include <climits>
#include <algorithm>
using namespace std;

#define rep(i,a,b) for (int i=(a);i<=(b);i++)
#define per(i,a,b) for (int i=(a);i>=(b);i--)

const int N=524288;
const int B=30;
const int S=16777216;
const int MIN=INT_MIN;

int n;
int a[N];

int pre[N],tot_Pre[N];
int suf[N];
int res;

namespace Trie {
    int rt,tot;
    struct Node {
        int c[2];
        Node(void) {
            c[0]=c[1]=0;
        }
    }tr[S];

    void Init(void) {
        rep(i,1,tot) tr[i]=Node();
        rt=tot=1;
    }

    void Ins(int &x,int num,int bit) {
        if (!x) x=++tot;
        if (bit==-1) return;
        Ins(tr[x].c[num>>bit&1],num,bit-1);
    }

    int Query_Max(int x,int num,int bit) {
        if (bit==-1) return 0;
        int dir=((num>>bit&1)^1);
        if (tr[x].c[dir]>0) {
            int t=Query_Max(tr[x].c[dir],num,bit-1);
            return t+(1<<bit);
        }
        else {
            int t=Query_Max(tr[x].c[dir^1],num,bit-1);
            return t;
        }
    }
}
using namespace Trie;

int rd(void) {
    int x=0,f=1; char c=getchar();
    while (!isdigit(c)) {
        if (c=='-') f=-1;
        c=getchar();
    }
    while (isdigit(c)) {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
    #endif

    n=rd();
    rep(i,1,n) a[i]=rd();
    rep(i,1,n) a[i]^=a[i-1];

    Init();
    rep(i,1,n) {
        Ins(rt,a[i-1],B);
        pre[i]=Query_Max(rt,a[i],B);
    }
    tot_Pre[1]=pre[1];
    rep(i,2,n)
        tot_Pre[i]=max(tot_Pre[i-1],pre[i]);

    Init();
    per(i,n,1) {
        Ins(rt,a[i],B);
        suf[i]=Query_Max(rt,a[i-1],B);
    }

    res=MIN;
    per(i,n,2) {
        int t=tot_Pre[i-1]+suf[i];
        res=max(res,t);
    }
    printf("%d\n",res);

    return 0;
}

【bzoj3439】Kpm的MC密码 - Trie + Treap启发式合并

传送门

http://www.lydsy.com/JudgeOnline/problem.php?id=3439

分析

把串反过来,那么相当于问每一个字符串的后缀中编号第\(k\)小的。

考虑建一棵Trie,那么就是询问某个子树内编号的第\(k\)小。

方法1:

转化为dfs序,用可持久化线段树来求解。

或者离线后乱搞。

方法2:

把Trie进行DFS,启发式合并。

代码

#include <cstdio>
#include <cstring>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <vector>
using namespace std;

#define rep(i,a,b) for (int i=(a);i<=(b);i++)

#define VI vector<int>
#define pb push_back

const int L=524288;
const int A=26;
const int N=131072;

int n;
char s[L];

int rt,tot;
struct Trie {
    int c[A];
    VI pt;
}tr[L];

int k[N];
int ans[N];

int root[L]; //int tot;
struct Treap {
    int c[2];
    int key,fix;
    int siz;
    Treap(int _key=0,int _siz=0) {
        c[0]=c[1]=0;
        key=_key,fix=rand();
        siz=_siz;
    }
}trp[L];
struct D {
    int c[2];
    D(void) {
        c[0]=c[1]=0;
    }
};

void Ins_Trie(int &x,char *s,int len,int id) {
    if (!x) x=++tot;
    if (!len) {
        tr[x].pt.pb(id);
        return;
    }
    Ins_Trie(tr[x].c[s[len]-'a'],s,len-1,id);
}

int New_Node(int key) {
    int x=++tot;
    trp[x]=Treap(key,1);
    return x;
}

void Update(int x) {
    trp[x].siz=trp[trp[x].c[0]].siz+trp[trp[x].c[1]].siz+1;
}

int Merge(int x1,int x2) {
    if (!x1) return x2;
    if (!x2) return x1;
    if (trp[x1].fix<trp[x2].fix) {
        trp[x1].c[1]=Merge(trp[x1].c[1],x2);
        Update(x1);
        return x1;
    }
    else {
        trp[x2].c[0]=Merge(x1,trp[x2].c[0]);
        Update(x2);
        return x2;
    }
}

D Split_Key(int x,int key) {
    D t; if (!x) return t;
    if (key<trp[x].key) {
        t=Split_Key(trp[x].c[0],key);
        trp[x].c[0]=t.c[1]; Update(x);
        t.c[1]=x;
    }
    else {
        t=Split_Key(trp[x].c[1],key);
        trp[x].c[1]=t.c[0]; Update(x);
        t.c[0]=x;
    }
    return t;
}

D Split(int x,int rk) {
    D t; if (!x) return t;
    if (rk<=trp[trp[x].c[0]].siz) {
        t=Split(trp[x].c[0],rk);
        trp[x].c[0]=t.c[1]; Update(x);
        t.c[1]=x;
    }
    else if (rk==trp[trp[x].c[0]].siz+1) {
        t.c[1]=trp[x].c[1];
        trp[x].c[1]=0; Update(x);
        t.c[0]=x;
    }
    else {
        t=Split(trp[x].c[1],rk-1-trp[trp[x].c[0]].siz);
        trp[x].c[1]=t.c[0]; Update(x);
        t.c[0]=x;
    }
    return t;
}

void Add_Point(int &to,int x) {
    D t=Split_Key(to,trp[x].key);
    to=Merge(t.c[0],x); to=Merge(to,t.c[1]);
}

void Add_Tree(int &to,int x) {
    if (!x) return;
    Add_Tree(to,trp[x].c[0]);
    Add_Tree(to,trp[x].c[1]);
    trp[x].c[0]=trp[x].c[1]=0; Update(x);
    Add_Point(to,x);
}

int Join(int x1,int x2) {
    if (trp[x1].siz<trp[x2].siz) swap(x1,x2);
    Add_Tree(x1,x2);
    return x1;
}

int Query_Kth(int x,int rk) {
    int siz=trp[x].siz;
    if (!(1<=rk&&rk<=siz)) return -1;
    D t1=Split(x,rk-1);
    D t2=Split(t1.c[1],1);
    int g=trp[t2.c[0]].key;
    x=Merge(t1.c[0],t2.c[0]); x=Merge(x,t2.c[1]);
    return g;
}

void DFS(int x) {
    rep(i,0,A-1)
        if (tr[x].c[i]>0)
            DFS(tr[x].c[i]);
    rep(i,0,A-1)
        if (tr[x].c[i]>0)
            root[x]=Join(root[x],root[tr[x].c[i]]);
    rep(i,1,tr[x].pt.size()) {
        int p=New_Node(tr[x].pt[i-1]);
        Add_Point(root[x],p);
    }
    rep(i,1,tr[x].pt.size()) {
        int p=tr[x].pt[i-1];
        ans[p]=Query_Kth(root[x],k[p]);
    }
}

int rd(void) {
    int x=0,f=1; char c=getchar();
    while (!isdigit(c)) {
        if (c=='-') f=-1;
        c=getchar();
    }
    while (isdigit(c)) {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
    #endif

    srand(time(0));

    n=rd(); rt=tot=1;
    rep(i,1,n) {
        scanf("%s",s+1);
        Ins_Trie(rt,s,strlen(s+1),i);
    }

    rep(i,1,n) k[i]=rd();
    DFS(rt);
    rep(i,1,n)
        printf("%d\n",ans[i]);

    return 0;
}

小结

(1)对于一棵树上的子树的离线询问,可以考虑使用启发式合并来求解。

(2)树上询问的处理技巧:

  • dfs序的性质,虚树
  • 树链剖分
  • LCT
  • 树上倍增,树上倍增dp
  • 树上莫队
  • 点分治
  • 离线dfs,启发式合并

【bzoj3261】最大异或和 - 可持久化Trie

代码

#include <cstdio>
#include <cctype>

#define rep(i,a,b) for (int i=(a);i<=(b);i++)

const int LEN=1048576;
const int S=16777216;
const int BIT=23;

int n,a[LEN];
int m;

int tot,rt[LEN],tms;
struct Trie {
    int c[2],cnt;
    Trie(void) {
        c[0]=c[1]=cnt=0;
    }
}tr[S];

int rd(void) {
    int x=0,f=1; char c=getchar();
    while (!isdigit(c)) {
        if (c=='-') f=-1;
        c=getchar();
    }
    while (isdigit(c)) {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}

int Ins(int x,int bit,int num) {
    int now=++tot; tr[now]=tr[x]; tr[now].cnt++;
    if (bit==-1) return now;
    tr[now].c[num>>bit&1]=Ins(tr[x].c[num>>bit&1],bit-1,num);
    return now;
}

int Query(int x1,int x2,int bit,int num) {
    if (bit==-1) return 0;
    int prefer=((num>>bit&1)^1);
    int cnt=tr[tr[x2].c[prefer]].cnt-tr[tr[x1].c[prefer]].cnt;
    if (cnt>0) {
        int t=Query(tr[x1].c[prefer],tr[x2].c[prefer],bit-1,num);
        return t+(1<<bit);
    }
    else {
        int t=Query(tr[x1].c[prefer^1],tr[x2].c[prefer^1],bit-1,num);
        return t;
    }
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
    #endif

    n=rd(),m=rd();
    rep(i,1,n) a[i]=rd();
    rep(i,2,n) a[i]^=a[i-1];
    rep(i,0,n)
        rt[i]=Ins(rt[i-1],BIT,a[i]);
    tms=0;

    rep(i,1,m) {
        scanf("\n"); char c=getchar();
        if (c=='A') {
            int x=rd(); a[n+1]=(x^a[n]);
            rt[n+1]=Ins(rt[n],BIT,a[n+1]);
            n++;
        }
        else {
            int l=rd(),r=rd(),x=rd();
            int ans=Query(rt[l-2>=0?l-2:n+1],rt[r-1],BIT,a[n]^x);
            printf("%d\n",ans);
        }
    }

    return 0;
}

【bzoj3166】ALO - Treap+可持久化Trie树

枚举次大值的坐标,那么可以通过前驱、后继得到一段区间。

#include <cstdio>
#include <cctype>
#include <ctime>
#include <algorithm>
using namespace std;

#define rep(i,a,b) for (int i=(a);i<=(b);i++)

const int N=65536;
const int S=2097152;
const int BIT=30;

int n;
int a[N];

int tot,rt[N];
struct Trie {
    int c[2]; int cnt;
    Trie(void) {
        c[0]=c[1]=cnt=0;
    }
}tr[S];

int ord[N]; int mx;
int root;
struct Treap {
    int c[2];
    int key,fix;
    int siz;
    Treap(int _key=0,int _siz=0) {
        c[0]=c[1]=0;
        key=_key,fix=rand();
        siz=_siz;
    }
}p[N];
struct D {
    int c[2];
    D(void) {
        c[0]=c[1]=0;
    }
};

int ans;

int rd(void) {
    int x=0,f=1; char c=getchar();
    while (!isdigit(c)) {
        if (c=='-') f=-1;
        c=getchar();
    }
    while (isdigit(c)) {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}

int Ins_Trie(int x,int bit,int num) {
    int now=++tot; tr[now]=tr[x]; tr[now].cnt++;
    if (bit==-1) return now;
    tr[now].c[num>>bit&1]=Ins_Trie(tr[x].c[num>>bit&1],bit-1,num);
    return now;
}

int Query_Trie(int x1,int x2,int bit,int num) {
    if (bit==-1) return 0;
    int prefer=((num>>bit&1)^1);
    int cnt=tr[tr[x2].c[prefer]].cnt-tr[tr[x1].c[prefer]].cnt;
    if (cnt>0) {
        int t=Query_Trie(tr[x1].c[prefer],tr[x2].c[prefer],bit-1,num);
        return t+(1<<bit);
    }
    else {
        int t=Query_Trie(tr[x1].c[prefer^1],tr[x2].c[prefer^1],bit-1,num);
        return t;
    }
}

int New_Node(int key) {
    int x=++tot;
    p[x]=Treap(key,1);
    return x;
}

void Update(int x) {
    p[x].siz=p[p[x].c[0]].siz+p[p[x].c[1]].siz+1;
}

int Merge(int x1,int x2) {
    if (!x1) return x2;
    if (!x2) return x1;
    if (p[x1].fix<p[x2].fix) {
        p[x1].c[1]=Merge(p[x1].c[1],x2);
        Update(x1);
        return x1;
    }
    else {
        p[x2].c[0]=Merge(x1,p[x2].c[0]);
        Update(x2);
        return x2;
    }
}

D Split_Key(int x,int key) {
    D t; if (!x) return t;
    if (key<p[x].key) {
        t=Split_Key(p[x].c[0],key);
        p[x].c[0]=t.c[1]; Update(x);
        t.c[1]=x;
    }
    else {
        t=Split_Key(p[x].c[1],key);
        p[x].c[1]=t.c[0]; Update(x);
        t.c[0]=x;
    }
    return t;
}

D Split(int x,int rk) {
    D t; if (!x) return t;
    if (rk<=p[p[x].c[0]].siz) {
        t=Split(p[x].c[0],rk);
        p[x].c[0]=t.c[1]; Update(x);
        t.c[1]=x;
    }
    else if (rk==p[p[x].c[0]].siz+1) {
        t.c[1]=p[x].c[1];
        p[x].c[1]=0; Update(x);
        t.c[0]=x;
    }
    else {
        t=Split(p[x].c[1],rk-1-p[p[x].c[0]].siz);
        p[x].c[1]=t.c[0]; Update(x);
        t.c[0]=x;
    }
    return t;
}

int Pre_Pre(int x) {
    D t1=Split_Key(root,x);
    int siz=p[t1.c[0]].siz,id;
    if (siz==1) {
        id=-1;
        root=Merge(t1.c[0],t1.c[1]);
    }
    else if (siz==2) {
        id=0;
        root=Merge(t1.c[0],t1.c[1]);
    }
    else {
        D t2=Split(t1.c[0],siz-3);
        D t3=Split(t2.c[1],1);
        id=p[t3.c[0]].key;
        root=Merge(t3.c[0],t3.c[1]);
        root=Merge(t2.c[0],root);
        root=Merge(root,t1.c[1]);
    }
    return id;
}

int Nxt_Nxt(int x) {
    D t1=Split_Key(root,x-1);
    int siz=p[t1.c[1]].siz,id;
    if (siz==1) {
        id=-1;
        root=Merge(t1.c[0],t1.c[1]);
    }
    else if (siz==2) {
        id=n+1;
        root=Merge(t1.c[0],t1.c[1]);
    }
    else {
        D t2=Split(t1.c[1],2);
        D t3=Split(t2.c[1],1);
        id=p[t3.c[0]].key;
        root=Merge(t3.c[0],t3.c[1]);
        root=Merge(t2.c[0],root);
        root=Merge(t1.c[0],root);
    }
    return id;
}

void Insert(int &rt,int key) {
    int x=New_Node(key);
    D t=Split_Key(rt,key);
    rt=Merge(t.c[0],x); rt=Merge(rt,t.c[1]);
}

int cmp(int x,int y) {
    return a[x]>a[y];
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
    #endif

    srand(2016+02+20);

    n=rd();
    rep(i,1,n) a[i]=rd();
    mx=*max_element(a+1,a+n+1);
    rep(i,1,n)
        rt[i]=Ins_Trie(rt[i-1],BIT,a[i]);

    rep(i,1,n) ord[i]=i;
    sort(ord+1,ord+n+1,cmp);
    tot=0;
    rep(i,1,n) {
        int loc=ord[i];
        Insert(root,loc);
        int x=Nxt_Nxt(loc);
        if (!(x==-1&&mx==a[loc])) {
            if (x==-1) x=n+1;
            if (loc+1<=x-1) {
                int t=Query_Trie(rt[loc],rt[x-1],BIT,a[loc]);
                ans=max(ans,t);
            }
        }
        x=Pre_Pre(loc);
        if (!(x==-1&&mx==a[loc])) {
            if (x==-1) x=0;
            if (x+1<=loc-1) {
                int t=Query_Trie(rt[x],rt[loc-1],BIT,a[loc]);
                ans=max(ans,t);
            }
        }
    }
    printf("%d\n",ans);

    return 0;
}

可持久化Trie & 可持久化平衡树 专题练习的更多相关文章

  1. 可持久化Trie模板

    如果你了解过 01 Trie 和 可持久化线段树(例如 : 主席树 ).那么就比较好去可持久化 Trie 可持久化 Trie 当 01 Trie 用的时候能很方便解决一些原本 01 Trie 不能解决 ...

  2. [您有新的未分配科技点]可,可,可持久化!?------0-1Trie和可持久化Trie普及版讲解

    这一次,我们来了解普通Trie树的变种:0-1Trie以及在其基础上产生的可持久化Trie(其实,普通的Trie也可以可持久化,只是不太常见) 先简单介绍一下0-1Trie:一个0-1Trie节点只有 ...

  3. HDU 4757 Tree(可持久化Trie+Tarjan离线LCA)

    Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Su ...

  4. 【BZOJ4260】 Codechef REBXOR 可持久化Trie

    看到异或就去想前缀和(⊙o⊙) 这个就是正反做一遍最大异或和更新答案 最大异或就是很经典的可持久化Trie,从高到低贪心 WA: val&(1<<(base-1))得到的并不直接是 ...

  5. HDU 4757 Tree(可持久化trie)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4757 题意:给出一棵树,节点有权值.每次询问x到y的路径上与z抑或的最大值. 思路:可持久化trie. ...

  6. 可持久化trie 学习总结

    QAQ 以前一直觉得可持久化trie很难,今天强行写了一发觉得还是蛮简单的嘛 自己的模板是自己手写的,写了几道题目并没有出过错误 THUSC的第二题的解法五貌似就是可持久化trie,时间复杂度O(60 ...

  7. [BZOJ 4103] [Thu Summer Camp 2015] 异或运算 【可持久化Trie】

    题目链接:BZOJ - 4103 题目分析 THUSC滚粗之后一直没有写这道题,从来没写过可持久化Trie,发现其实和可持久化线段树都是一样的.嗯,有些东西就是明白得太晚. 首先Orz ZYF-ZYF ...

  8. bzoj 2741: 【FOTILE模拟赛】L 分塊+可持久化trie

    2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1116  Solved: 292[Submit][Status] ...

  9. bzoj 2741 分块+可持久化trie

    多个询问l,r,求所有子区间异或和中最大是多少 强制在线 做法: 分块+可持久化trie 1.对于每块的左端点i,预处理出i到任意一个j,()i,j)间所有子区间异或和中最大为多少,复杂度O(\(n\ ...

随机推荐

  1. Web自定义协议,BS端启动CS端,

    实例 1.准备CS项目,windows窗体应用程序,拖进来一个label控件来接受BS的参数,并显示,右击生成,复制该文件的bin目录下的exe,例如放在以下路径,例如C:\\simu\\下, 2.编 ...

  2. BZOJ 3551 Peaks加强版

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3551 题意:给出一个图,n个点,m条边.边有权值点也有权值.若干询问,(v,x,k),问从 ...

  3. 【转载】OGRE 内存管理

    原文:OGRE 内存管理 Ogre引擎中与内存管理相关的文件大致有以下几个(只列出头文件) OgreAlignedAllocator.h OgreMemoryAllocatedObject.h Ogr ...

  4. [POJ1830]开关问题(高斯消元,异或方程组)

    题目链接:http://poj.org/problem?id=1830 题意:中文题面,求的是方案数. 首先可以知道, 如果方案数不止一个的话,说明矩阵行列式值为0,即存在自由变元,由于变量只有两种状 ...

  5. firefox渗透师必备的利器

    工欲善必先利其器,firefox一直是各位渗透师必备的利器,小编这里推荐34款firefox渗透测试辅助插件,其中包含渗透测试.信息收集.代理.加密解密等功能. 1:Firebug Firefox的 ...

  6. EF实体框架常见问题

    1,无法为具有固定名称“System.Data.SqlClient”的 ADO.NET 提供程序加载在应用程序配置文件中注册的实体框架提供程序类型“System.Data.Entity.SqlServ ...

  7. ServiceStack.OrmLite 笔记10-group having 分页orderby等

    group having 分页等 var ev = OrmLiteConfig.DialectProvider.SqlExpression(); group的使用 同sql一样,注意group分组的字 ...

  8. JVM 1.类的加载、连接、初始化

    Java类的加载是由类加载器来完成的,过程如下: 首先,加载是把硬盘.网络.数据库等的class文件中的二进制数据加载到内存的过程,然后会在Java虚拟机的运行时数据区的堆区创建一个Class对象,用 ...

  9. C# 线程(六):定时器

    From : http://kb.cnblogs.com/page/42532/ Timer类:设置一个定时器,定时执行用户指定的函数. 定时器启动后,系统将自动建立一个新的线程,执行用户指定的函数. ...

  10. 关于js运动的一些总结

    js运动实现,有两种.一种是速度版,另一种是时间版. 速度版是通过对速度的加减乘除,得出元素的运动数据.时间版是通过对时间进行Tween公式运算,得出元素的运动数据. 速度版运动优点:容易在运动过程中 ...