1 条题解

  • 0
    @ 2025-8-24 21:28:07

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Flaranis
    “无尽的风之轨迹”

    搬运于2025-08-24 21:28:06,当前版本为作者最后更新于2018-01-07 16:12:23,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    这应该是平衡树维护区间翻转的模板题吧

    对于一次翻转(L , R)

    主流的做法是Splay把编号为L-1的节点旋转到根

    再把编号为R+1的节点旋转到根的右节点

    这样根的右节点的左子树全为L---R,打上翻转标记即可

    顺便再拓展一种算法,也就是我写的非选择treap

    核心操作是split和merge

    split是从某一位置把平衡树拆开,返回两个值即两根

    merge是合并两个子树,要求保证某一子树元素严格小于另一子树

    这样翻转区间L---R的时候

    可以通过split拆出树1---L-1,树L---R,树R+1---n(均为编号)

    在第二棵树的根上打上翻转标记

    按顺序合并三棵树,在合并过程中下放标记

    即可以复杂度O(len*log(len))的复杂度水过此题

    以下是我的代码:

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<ctime>
    #define rt register int
    #define ll long long
    #define r read()
    using namespace std;
    inline int read()
    {
        int x = 0; int zf = 1; char ch;
        while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
        if (ch == '-') zf = -1, ch = getchar();
        while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
    }
    int i,j,m,n,x,y,z,cnt,all,num,Root;
    struct points{
        int ls,rs,val,size,lazy;
    }a[10010];
    struct two{int ls,rs;};
    inline void up(const int x)
    {
        a[x].size=a[a[x].ls].size+a[a[x].rs].size+1;
    }
    inline void down(const int x)
    {
        if(!a[x].lazy)return;
        swap(a[x].ls,a[x].rs);
        a[a[x].ls].lazy^=1;
        a[a[x].rs].lazy^=1;
        a[x].lazy=0;
    }
    inline int merge(const int x,const int y)//x < y
    {
        if(!x)return y;if(!y)return x;
        down(x);down(y);
        if(a[x].val>a[y].val)
        {
            a[y].ls=merge(x,a[y].ls);
            up(y);
            return y;
        }
        else
        {
            a[x].rs=merge(a[x].rs,y);
            up(x);
            return x;        
        }
    }
    two split(const int x,const int val)//rank 1...val ;val+1...n
    {
        two ret={0,0};down(x);
        if(!x)return ret;rt p=a[a[x].ls].size+1;
        if(p<=val)
        {
            ret=split(a[x].rs,val-p);
            a[x].rs=ret.ls;
            ret.ls=x;
        }
        else
        {
            ret=split(a[x].ls,val);
            a[x].ls=ret.rs;
            ret.rs=x;
        }up(x);
        return ret;
    }
    char v[10010],k,c[10010];short len1,len2;
    void writes(const int x)
    {
        down(x);
        if(a[x].ls)writes(a[x].ls);
        putchar(c[x]);
        if(a[x].rs)writes(a[x].rs);
    }
    inline int newnode(const int x)
    {
        cnt++;a[cnt].size=1;a[cnt].val=rand();return cnt;
    }
    inline void insert(const int val)
    {
        two u=split(Root,val);
        Root=merge(merge(u.ls,u.rs),newnode(val));
    }
    inline void solve(const int L,const int R)
    {
        two p1=split(Root,L-1); 
        two p2=split(p1.rs,R-a[p1.ls].size);
        a[p2.ls].lazy^=1; 
        Root=merge(p1.ls,merge(p2.ls,p2.rs));
    }
    int main()
    {
        srand(time(0));j=0;
        scanf("%s %s",v+1,c+1);rt len1=strlen(v+1);n=strlen(c+1);
        for(rt i=1,j=1;i<=n;i++,j++)
        {
            if(j>len1)j-=len1;
            if(v[j]<='Z')k=v[j]-'A';else k=v[j]-'a';
            if(c[i]<='Z')k+=c[i]-'A';else k+=c[i]-'a';
            if(k>=26)k-=26;
            if(c[i]<='Z')c[i]='A'+k;else c[i]='a'+k;
        }
        for(rt i=1;i<=n;i++)insert(i);
        for(m=r;m;m--)
        {
            x=r;y=r;
            solve(x,y);
        }
        writes(Root);
        return 0;
    }
    
    
    • 1

    信息

    ID
    683
    时间
    1000ms
    内存
    125MiB
    难度
    2
    标签
    递交数
    0
    已通过
    0
    上传者