zoukankan      html  css  js  c++  java
  • 板子们~缓慢更新

    1.树链剖分

    #include<iostream>
    #include<cstdio>
    #define maxn 1000001
    using namespace std;
    int num,head[maxn],dep[maxn],fa[maxn],siz[maxn];
    int son[maxn],id[maxn],cnt,wt[maxn],w[maxn],top[maxn];
    int sum[maxn],mo,laz[maxn],n,res,m,number;
    
    struct asd{
        int next;
        int to;
    } a[maxn<<1];
    
    inline void add(int x,int y)
    {
        a[++num].next=head[x];
        a[num].to=y;
        head[x]=num;
    }
    
    inline void dfs1(int x,int father,int deep)
    {
        dep[x]=deep; fa[x]=father; siz[x]=1;
        int maxson=-1;
        for(int i=head[x];i;i=a[i].next)
        {
            int to=a[i].to; if(to==father) continue;
            dfs1(to,x,deep+1);
            siz[x]+=siz[to];
            if(siz[to]>maxson)
            {
                son[x]=to;
                maxson=siz[to];
            }
        }
    }
    
    inline void dfs2(int x,int topp)
    {
        id[x]=++cnt; wt[cnt]=w[x]; top[x]=topp;
        if(!son[x]) return;
        dfs2(son[x],topp);
        for(int i=head[x];i;i=a[i].next)
        {
            if(a[i].to==fa[x] || a[i].to==son[x])
                continue;
            dfs2(a[i].to,a[i].to);
        }
    }
    
    inline void build(int rt,int l,int r)
    {
        if(l==r)
        {
            sum[rt]=wt[l];
            sum[rt]%=mo;
            return;
        }
        int mid=l+r>>1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
        sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mo;
    }
    
    inline void pushdown(int rt,int ln,int rn)
    {
        if(laz[rt])
        {
            laz[rt<<1]+=laz[rt];
            laz[rt<<1|1]+=laz[rt];
            sum[rt<<1]+=laz[rt]*ln;
            sum[rt<<1|1]+=laz[rt]*rn;
            sum[rt<<1]%=mo;
            sum[rt<<1|1]%=mo;
            laz[rt]=0;
        }
    }
    
    inline void update(int rt,int l,int r,int L,int R,int k)
    {
        if(L<=l && r<=R)
        {
            laz[rt]+=k;
            sum[rt]+=k*(r-l+1);
            return;
        }
        int mid=l+r>>1;
        pushdown(rt,mid-l+1,r-mid);
        if(L<=mid) update(rt<<1,l,mid,L,R,k);
        if(R>mid) update(rt<<1|1,mid+1,r,L,R,k);
        sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mo;
    }
    
    inline void change(int x,int y,int k)
    {
        k%=mo;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            update(1,1,n,id[top[x]],id[x],k);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y]) swap(x,y);
        update(1,1,n,id[x],id[y],k);
    }
    
    inline void query(int rt,int l,int r,int L,int R)
    {
        if(L<=l && r<=R)
        {
            res+=sum[rt];
            res%=mo;
            return;
        }
        int mid=l+r>>1;
        pushdown(rt,mid-l+1,r-mid);
        if(L<=mid) query(rt<<1,l,mid,L,R);
        if(R>mid) query(rt<<1|1,mid+1,r,L,R);
        sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mo;
    }
    
    inline int addup(int x,int y)
    {
        int ans=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            res=0;
            query(1,1,n,id[top[x]],id[x]);
            ans+=res; ans%=mo;
            x=fa[top[x]];
        }
        if(dep[x]>dep[y]) swap(x,y);
        res=0;
        query(1,1,n,id[x],id[y]);
        ans+=res;
        return ans%=mo;
    }
    
    inline void changeS(int x,int k)
    {
        update(1,1,n,id[x],id[x]+siz[x]-1,k);
    }
    
    inline int addupS(int x)
    {
        res=0;
        query(1,1,n,id[x],id[x]+siz[x]-1);
        return res;
    }
    
    int main()
    {
        cin>>n>>m>>number>>mo;
        for(int i=1;i<=n;i++) scanf("%d",&w[i]);
        for(int i=1;i<=n-1;i++)
        {
            int aa,bb;
            scanf("%d%d",&aa,&bb);
            add(aa,bb); add(bb,aa);
        }
        dfs1(number,0,1);
        dfs2(number,number);
        build(1,1,n);
        while(m--)
        {
            int k,x,y,z;
            scanf("%d",&k);
    
            if(k==1)
            {
                scanf("%d%d%d",&x,&y,&z);
                change(x,y,z);
            }
            if(k==2)
            {
                scanf("%d%d",&x,&y);
                printf("%d
    ",addup(x,y));
            }
            if(k==3)
            {
                scanf("%d%d",&x,&y);
                changeS(x,y);
            }
            if(k==4)
            {
                scanf("%d",&x);
                printf("%d
    ",addupS(x));
            }
        }
    }
    树链剖分

    2.SA

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 1000010
    using namespace std;
    int num[maxn],sa[maxn],se[maxn],rk[maxn],n,m,height[maxn];
    char ch[maxn];
    
    void debug()
    {
        printf("*****************
    ");
        printf("下标");for(int i=1;i<=n;i++) printf("%d ",i);printf("
    ");
        printf("sa  ");for(int i=1;i<=n;i++) printf("%d ",sa[i]);printf("
    ");
        printf("rk ");for(int i=1;i<=n;i++) printf("%d ",rk[i]);printf("
    ");
        printf("se  ");for(int i=1;i<=n;i++) printf("%d ",se[i]);printf("
    ");
    }
    
    inline void rsort()
    {
        for(int i=0;i<=m;i++) num[i]=0;
        for(int i=1;i<=n;i++) num[rk[i]]++;
        for(int i=1;i<=m;i++) num[i]+=num[i-1];
        for(int i=n;i>=1;i--) sa[ num[ rk[ se[i]]]--]=se[i];
    }
    
    inline void SA()
    {
        rsort();
        for(int k=1,tot=1; tot<n; m=tot,k<<=1)
        {
            tot=0;
            for(int i=1;i<=k;i++) se[++tot]=n-k+i;
            for(int i=1;i<=n;i++) if(sa[i]>k) se[++tot]=sa[i]-k;
            rsort();
            swap(rk,se);
            rk[sa[1]]=tot=1;
            for(int i=2;i<=n;i++)
                if(se[sa[i-1]]==se[sa[i]] && se[sa[i]+k]==se[sa[i-1]+k])
                    rk[sa[i]]=tot;
                else rk[sa[i]]=++tot;
        }
        for(int i=1;i<=n;i++) printf("%d ",sa[i]);
    }
    
    inline void HEIGHT()
    {
        int k=0;
        for(int i=1;i<=n;i++) rk[sa[i]]=i;
        for(int i=1,j;i<=n;i++)
        {
            if(rk[i]==1) continue;
            if(k) --k;
            j=sa[rk[i]-1];
            while(j+k<=n && i+k<=n && ch[i+k]==ch[j+k]) k++;
            height[rk[i]]=k;
        }
        for(int i=1;i<=n;i++) printf("%d ",height[i]);
    }
    
    int main()
    {
        cin>>ch;
        n=strlen(ch); m=127;
        for(int i=0;i<=n-1;i++)
        {
            rk[i+1]=ch[i]-48;
            se[i+1]=i+1;
        }
        SA();
    //    HEIGHT();
        return 0;
    }
    后缀数组

    3.KMP

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    char s[1000001],t[1000001];
    int m,n,next[1000001];
    int main()
    {
        scanf("%s",s);
        n=strlen(s);
        scanf("%s",t);
        m=strlen(t);
    
        next[0]=-1;
        int k=-1;
        for(int i=1;i<m;i++)
        {
            while(k>=0 && t[i]!=t[k+1]) k=next[k];
            if(t[i]==t[k+1]) k++;
            next[i]=k;
        }
    
        int kk=-1; int ans=0;
        for(int i=0;i<n;i++)
        {
            while(kk>=0 && s[i]!=t[kk+1]) kk=next[kk];
            if(s[i]==t[kk+1]) kk++;
            if(kk==m-1) { cout<<i+1-m+1<<endl;kk=next[kk]; }
        }
        for(int i=0;i<=m-1;i++)
            cout<<next[i]+1<<" ";
        return 0;
    }
    KMP

    4.treap

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    struct asd{
        int ls,rs; //左右儿子
        int size; // 统计包含自身的节点个数
        int cnt; // 统计自己出现的次数 
        int dep; // 随机出来的优先级
        int val; // 自身的值 
    } tree[10000001];
    int root,size,n,ans;
    
    void update(int k) // 更新节点的个数
    {
        tree[k].size=tree[tree[k].ls].size+tree[tree[k].rs].size+tree[k].cnt;
        return; // 记住上面的式子加上自身的重复 
    }
    
    void left(int &k) // 将其的右儿子左转 
    {
        int rson=tree[k].rs;
        tree[k].rs=tree[rson].ls; // 将自己的右儿子变为其右儿子的左儿子
        tree[rson].ls=k; // 把自己变为其右儿子的左儿子
        tree[rson].size=tree[k].size; // 然后在统计子树大小
        update(k); // 并且更新其节点
        k=rson; // 这个是将k的父亲把k这个儿子改成了rson 
    }
    
    /*
    解释一下这个k到底是什么
    其实这个k相当于一个地址,它所储存了一堆信息,然后我们修改了这个指针所对应的值
    但没有改变这个指针里面的值,只是修改了指针让它指向了另外一个点。指向了另个位置所对应的值
    */
    
    void right(int &k)
    {
        int lson=tree[k].ls;
        tree[k].ls=tree[lson].rs;
        tree[lson].rs=k;
        tree[lson].size=tree[k].size;
        update(k);
        k=lson;
    } // 与left同理 
    
    void insert(int &k,int x)
    {
        if(k==0) // 已经递归到了叶子节点
        {
            size++; // 总的节点数+1
            k=size; tree[k].size=1; tree[k].cnt=1;
            tree[k].val=x; tree[k].dep=rand(); // 随机一个堆:小根堆 
            return; 
        }
        tree[k].size++; // 如果没到叶节点,说明此节点可包含所插入的数 
        if(tree[k].val==x) { tree[k].cnt++; return; } // 如果相等直接加上重复 
        if(tree[k].val<x) // 如果小于放到右子树上 
        {
            insert(tree[k].rs,x); // 插入右子树
            if(tree[tree[k].rs].dep<tree[k].dep) // 违反了堆的性质
                left(k); // 将k的rson转到k上去,把k转下来 
        }
        if(tree[k].val>x) // 放到左子树
        {
            insert(tree[k].ls,x);
            if(tree[tree[k].ls].dep<tree[k].dep)
                right(k);
        }
    }
    
    void delet(int &k,int x) // 删除值等于x这个节点
    {
        if(tree[k].val==x) // 找到了这个节点
        {
            if(tree[k].cnt>1) // 如果有重复的话就直接操作
            { tree[k].cnt--; tree[k].size--; return; }
            if(tree[k].ls*tree[k].rs==0) // 如果他没有重复且左右子树至少有一个0
                k=tree[k].ls+tree[k].rs;
            else if(tree[tree[k].ls].dep<tree[tree[k].rs].dep) // 两个子树都有,找到优先级最大然后转上去
                 { right(k); delet(k,x); } // 此时的k已经变为叶子节点就可以直接删去
                 else { left(k); delet(k,x); }
        }
        else
        {
            if(tree[k].val>x) { tree[k].size--; delet(tree[k].ls,x); }
            else { tree[k].size--; delet(tree[k].rs,x); } // 一直找下去直到k为叶子节点然后删除 
        }
    }
    
    int check1(int &k,int x)
    {
        if(k==0) return 0;
        if(tree[k].val==x) return tree[tree[k].ls].size+1; // 如果找到了那么就是其左子树的个数+1
        if(tree[k].val<x) return tree[tree[k].ls].size+tree[k].cnt+check1(tree[k].rs,x);
        if(tree[k].val>x) return check1(tree[k].ls,x);
    }
    
    int check2(int &k,int x) // 寻找排名为x的值
    {
        if(x<=tree[tree[k].ls].size) return check2(tree[k].ls,x);
        // 如果排名小于当前节点左子树的大小,就在他的左子树中找 
        if(x>tree[tree[k].ls].size+tree[k].cnt) return check2(tree[k].rs,x-tree[tree[k].ls].size-tree[k].cnt);
        // 如果排名大于当前节点左子树+他的重复的大小,就在他的右子树中找
        return tree[k].val; 
    }
    
    void min_max(int k,int x) // 找比x小的最大数
    {
        if(k==0) return; // 如果找到没有
        if(tree[k].val<x) // 如果比此节点大
        { ans=k; min_max(tree[k].rs,x); } // 先赋值,然后再去找更优解 
        else min_max(tree[k].ls,x); // 如果小了就只能在其左子树中找 
    }
    
    void max_min(int k,int x) // 找比x大的最小值
    {
        if(k==0) return;
        if(tree[k].val>x) { ans=k; max_min(tree[k].ls,x); }
        else max_min(tree[k].rs,x);
    } 
    
    int main()
    {
        cin>>n; int number,x;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&number,&x);
            if(number==1) insert(root,x);
            if(number==2) delet(root,x);
            if(number==3) printf("%d
    ",check1(root,x));
            if(number==4) printf("%d
    ",check2(root,x));
            if(number==5) { min_max(root,x); printf("%d
    ",tree[ans].val); }
            if(number==6) { max_min(root,x); printf("%d
    ",tree[ans].val); }
        }
        return 0;
    }
    treap

    5.splay(大常数平衡树)

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int root,cnt,n,ans;
    
    struct asd{
        int s[2];
        int fa;
        int key;
        int cnt;
        int pos;
        int size;
    } tree[2000001];
    
    inline void clear(int x) { tree[x].s[0]=tree[x].s[1]=tree[x].fa=tree[x].cnt=tree[x].key=tree[x].size=0; }
    // 将当前点的各项值都清0 (用于删除之后)
    
    inline int get(int x) { return tree[tree[x].fa].s[1]==x; }
    // 判断当前点是他父节点的左儿子还是右儿子
     
    inline void pushup(int x)
    {
        if(x)
        {
            tree[x].size=tree[x].cnt;
            if(tree[x].s[0]) tree[x].size+=tree[tree[x].s[0]].size;
            if(tree[x].s[1]) tree[x].size+=tree[tree[x].s[1]].size;
        }
    }
    // 更新当前点的size值 (用于发生修改之后)
    
    inline void rotate(int x)
    {
        int old=tree[x].fa,oldf=tree[old].fa,which=get(x);
        tree[old].s[which]=tree[x].s[which^1];
        if(tree[old].s[which]) tree[tree[old].s[which]].fa=old;
        tree[x].s[which^1]=old;
        tree[old].fa=x;
        tree[x].fa=oldf;
        if(oldf) tree[oldf].s[tree[oldf].s[1]==old]=x;
        pushup(old); pushup(x);
    }
    // 一共包含三个步骤。。。真●恶心 
    // step1:找出要变动节点(D)的父亲结点(B)以及父亲的父亲(A)并记录。。。判断D是B的左结点还是右结点
    // step2:转换节点保证二叉树的大小关系不变。。。笼统概括(雾 ↓
    /* 
    我们已经判断了D是B的左儿子还是右儿子,设这个关系为K;
    将D与K关系相反的儿子的父亲记为B与K关系相同的儿子(这里即为D的右儿子的父亲记为B的左儿子)
    将D与K关系相反的儿子的父亲即为B(这里即为把G的父亲记为B)
    将B的父亲即为D
    将D与K关系相反的儿子记为B(这里即为把D的右儿子记为B)
    将D的父亲记为A。
    最后要判断,如果A存在(即rotate到的位置不是根的话),要把A的儿子记为D。
    显而易见,rotate之后所有牵涉到变化的父子关系都要改变。
    以上的树需要改变四对父子关系,BG DG BD AB,需要三个操作(BG BD AB)。
    */
    // step3:pushup一下当前点和各个父结点的各个值
    
    inline void splay(int x)
    {
        for(int fa;fa=tree[x].fa;rotate(x))
            if(tree[fa].fa)
                rotate(get(x)==get(fa) ? fa:x);
        root=x;
    }
    // 实际上splay只是rotate的发展。。。就是不停的rotate。。。
    // 因为没有确切的停止状态。。。此处代码直接到根
    // 当然splay也会遇到一些特殊的情况。。。
    // 如果是三点一条链的情况就需要先rotate x的父亲
    // 不这样做会形成单旋使平衡树失衡。。。 
    /*
    inline void splay(int x,int tar)
    {
        for(int fa;(fa=tree[x].fa!=tar;rotate(x))
            if(tree[fa]!=tar)
                rotate(get(x)==get(fa) ? fa:x);
        if(!tar) root=x;
    }
    */
    
    inline void insert(int x)
    {
        if(root==0)
        {
            root=++cnt;
            tree[root].s[0]=0; tree[root].s[1]=0; tree[root].fa=0;
            tree[root].key=x; tree[root].cnt=1; tree[root].size=1;
            return;
        }
        int now=root,fa=0;
        while(1)
        {
            if(tree[now].key==x)
            {
                tree[now].cnt++;
                pushup(now); pushup(fa);
                splay(now); break;
            }
            fa=now; now=tree[now].s[tree[now].key<x];
            if(now==0)
            {
                int k=++cnt;
                tree[k].s[0]=tree[k].s[1]=0;
                tree[k].key=x;
                tree[k].size=1;
                tree[k].cnt=1;
                tree[k].fa=fa;
                tree[fa].s[tree[fa].key<x]=k;
                pushup(fa); splay(k);
                break;
            }
        }
    }
    // 如果k==0 即树为空,做一些处理直接返回。。。
    //  如果遇到一个结点的关键字等于当前要插入的点的话
    // 我们就等于把这个结点加了一个权值
    // 因为在二叉搜索树中是不可能出现两个相同的点
    // 并且要将当前点和它父亲结点的各项值更新一下。做一下splay。
    // 如果已经到了最底下了,那么就可以直接插入
    // 整个树的大小要+1,新结点的左儿子右儿子(虽然是空)父亲还有各项值要一一对应
    // 并且最后要做一下他父亲的update(做他自己的没有必要)。做一下splay
    
    inline int pre() { int x=tree[root].s[0]; while(tree[x].s[1]) x=tree[x].s[1]; return x; }
    
    inline int nxe() { int x=tree[root].s[1]; while(tree[x].s[0]) x=tree[x].s[0]; return x; }
    
    inline int find(int x) // 查询x的排名 
    {
        int k=root;ans=0;
        while(1)
        {
            if(x<tree[k].key) k=tree[k].s[0];
            else
            {
                ans+=(tree[k].s[0] ? tree[tree[k].s[0]].size : 0);
                if(tree[k].key==x) { splay(k); return ans+1; }
                ans+=tree[k].cnt;
                k=tree[k].s[1];
            }
        }
    }
    // 
    
    inline int findx(int x) // 查询排名为x的点 
    {
        int k=root;
        while(1)
        {
            if(x<=tree[tree[k].s[0]].size && tree[k].s[0]) k=tree[k].s[0];
            else
            {
                x-=tree[tree[k].s[0]].size+tree[k].cnt;
                x=max(x,0);
                if(!x) return tree[k].key;
                k=tree[k].s[1];
            }
        }
    }
    //
    
    inline void delet(int x)
    {
        int hhh=find(x);
        if(tree[root].cnt>1) { tree[root].cnt--; return; }
        if(!tree[root].s[0] && !tree[root].s[1]) {clear(root); root=0; return; }
        if(!tree[root].s[0]) { int oldf=root; root=tree[root].s[1]; tree[root].fa=0; clear(oldf); return; }
        else
        if(!tree[root].s[1]) { int oldf=root; root=tree[root].s[0]; tree[root].fa=0; clear(oldf); return; }
        int leftbig=pre(),oldf=root;
        splay(leftbig);
        tree[tree[oldf].s[1]].fa=root;
        tree[root].s[1]=tree[oldf].s[1];
        clear(oldf); pushup(root); return;
    }
    
    int main()
    {
        cin>>n;
        int opt,x;
        for(int i=1;i<=n;i++)
        {
    
            scanf("%d%d",&opt,&x);
            if(opt==1) insert(x);
            if(opt==2) delet(x);
            if(opt==3) printf("%d
    ",find(x));
            if(opt==4) printf("%d
    ",findx(x));
            if(opt==5) { insert(x); printf("%d
    ",tree[pre()].key); delet(x); }
            if(opt==6) { insert(x); printf("%d
    ",tree[nxe()].key); delet(x); }
        }
    }
    splay(大常数平衡树)

    6.splay(区间翻转)

    #include<iostream>
    #include<cstdio>
    #define INF 99999999
    #define maxn 1000001
    using namespace std;
    
    int cnt,w[maxn],root,n,m,sz;
    bool mark[maxn];
    
    struct asd{
        int s[2];
        int key;
        int fa;
        int size;
    } tree[maxn<<1];
    
    inline void pushup(int x) { tree[x].size=tree[tree[x].s[0]].size+tree[tree[x].s[1]].size+1; }
    inline void swap(int &x,int &y) { int t=x; x=y; y=t; }
    inline bool get(int x) { return tree[tree[x].fa].s[1]==x; }
    
    inline void pushdown(int x)
    {
        if(x && mark[x])
        {
            mark[tree[x].s[0]]^=1;
            mark[tree[x].s[1]]^=1;
            swap(tree[x].s[0],tree[x].s[1]); // ???
            mark[x]=0;
        }
    }
    
    inline int build(int fa,int l,int r)
    {
        if(l>r) return 0;
        int mid=l+r>>1;
        int now=++sz;
        tree[now].key=w[mid];
        tree[now].fa=fa;
        mark[now]=0;
        tree[now].s[0]=build(now,l,mid-1);
        tree[now].s[1]=build(now,mid+1,r);
        pushup(now);
        return now;
    }
    
    inline void rotate(int x)
    {
        int old=tree[x].fa , oldf=tree[old].fa , which=get(x);
        pushdown(old); pushdown(x);
        tree[old].s[which] = tree[x].s[which^1];
        if (tree[old].s[which]) tree[tree[old].s[which]].fa = old;
        tree[old].fa=x;
        tree[x].fa=oldf;
        tree[x].s[which^1]=old;
        if(oldf) tree[oldf].s[tree[oldf].s[1]==old] = x;
        pushup(old); pushup(x);
    }
    
    inline void splay(int x,int tar)
    {
        for(int fa;(fa=tree[x].fa)!=tar;rotate(x))
            if(tree[fa].fa!=tar)
                rotate(get(fa)==get(x) ? fa:x);
        if(!tar) root=x;
    }
    
    inline int findx(int k,int x)
    {
        while(1)
        {
            pushdown(k);
            if(x<=tree[tree[k].s[0]].size) k=tree[k].s[0];
            else
            {
                x-=tree[tree[k].s[0]].size+1;
                if(!x) return k;
                k=tree[k].s[1];
            }
        }
    }
    
    /*
    int findx(int k,int x)
    {
        while(1)
        {
            pushdown(k);
            if(x<=tree[tree[k].s[0]].size) k=tree[k].s[0];
            else
            {
                x-=tree[tree[k].s[0]].size;
                if(x==1)
                {
    //                splay(k,0); // 加不加好像都行。。。但是这个可以维护树高 
                    return k;
                }
                k=tree[k].s[1];
                --x;
            }
        }
    }
    */
    
    inline void print(int x)
    {
        pushdown(x);
        if(tree[x].s[0]) print(tree[x].s[0]);
        if(tree[x].key!=-INF && tree[x].key!=INF) printf("%d ",tree[x].key);
        if(tree[x].s[1]) print(tree[x].s[1]);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) w[i+1]=i;
        w[1]=-INF; w[n+2]=INF;
        root=build(0,1,n+2);
        int x,y;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            int x1=findx(root,x);
            int y1=findx(root,y+2);
            splay(x1,0);
            splay(y1,x1);
            mark[tree[tree[root].s[1]].s[0]]^=1;
        }
        print(root);
    }
    
    // 假如我们要在Splay中修改区间的话,可以先查找siz值为l与r+2的两个节点
    // 将一个旋转到根,另一个旋转到根的左儿子上
    // 则要修改的区间就是根的右孩子的左子树,直接打标记即可
    splay区间翻转

     7.ST标

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    using namespace std;
    int n,q,a[100001],L,R,f1[100001][21];
    inline void ST()
    {
        int k=log(n)/log(2);
    //  每次并不是增加一个长度,而是使用倍增的思想,每次增加2^i个长度。
        for(register int i=1;i<=n;i++) f1[i][0]=a[i];
        for(register int j=1;j<=k;j++)
            for(register int i=1;i+(1<<j)-1<=n;i++)
            {
                f1[i][j]=max(f1[i][j-1],f1[i+(1<<(j-1))][j-1]);
            }
    }
    inline int RMQ(int L,int R)
    {
        int k=log(R-L+1)/log(2);
        return max(f1[L][k],f1[R-(1<<k)+1][k]);
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        for(register int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        ST();
        for(register int i=1;i<=q;i++)
        {
            scanf("%d%d",&L,&R);
            printf("%d
    ",RMQ(L,R));
        }
    }
    ST表
  • 相关阅读:
    TOEFL资料 280多个
    Eclipse搭建J2ME开发环境
    Session.Abandon和Session.Clear有何不同
    进程之同步、互斥PV操作笔记
    Windows Mobile 6.5 实现联系人分组显示
    关于数据库的版本控制
    xhtml的布局,满屏,高度自适应
    MOSS 项目模板
    DNN中与模块相关的信息
    J2EE学习笔记
  • 原文地址:https://www.cnblogs.com/zzzyc/p/8685843.html
Copyright © 2011-2022 走看看