P5350 序列 可持久化fhq

题意:

戳这里

分析:

  • 前置芝士: 可持久化文艺平衡树

我们发现 \(1,2,3,6\) 这些操作就是 \(fhq\) 的基操,模板题做过就会

所以我们只需要考虑 \(4,5\) 操作

对于 \(5\) 操作就直接裂成 \(5\) 段,然后交换第 \(2\)\(4\) 段,再合上就好了

对于 \(4\) 操作,我们发现因为 \(fhq\) 不支持插入一段区间,只能一个元素一个元素并上去,那么复杂度就会变成 \(O(qn)\) ,所以我们需要记一下历史版本,然后直接复制历史版本的元素信息到对应的位置上,这样就相当于加上了一段区间

然后你就会得到 \(MLE\) 的好成绩,做了 可持久化\(fhq\)/可持久化文艺平衡树 就会发现,这道题的空间小的离谱,只有 \(128M\) 也就是说我们不可能把所有的历史版本都存下来,那么只能在空间达到一定程度后重构 \(fhq\) 把所有 \(4\) 操作带来的影响加上去,来维持空间复杂度,具体来说就是遍历整个 \(fhq\) 把所有标记都清除后重建一个 \(fhq\)

tip:

对于可持久化 \(fhq\) ,需要在任何改变平衡树形态和元素信息的地方记录一下历史版本,比如 \(pushdown,merge,split\) 的时候

代码:

这应该是我写过的最长的数据结构题,足足 \(7k\) 代码

#include<bits/stdc++.h>

using namespace std;

namespace zzc
{
	#define getchar() (tt == ss && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
	char In[1 << 20], *ss=In, *tt=In;
	inline int read()
	{
		int x=0,f=1;char ch=getchar();
		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
		return x*f;
	}
	
    const int maxn = 3e6+5;
    const int mod = 1e9+7;
    int n,m,num;
    int tmp[maxn];

    namespace fhq_treap
    {
        int cnt,rt;
        struct node
        {
            int lc,rc,sum,val,siz,rnd,add,tag,rev;
        }t[maxn];

        inline int new_node(int x=0)
        {
            int u=++cnt;
            t[u].val=t[u].sum=x;
            t[u].siz=1;
            t[u].tag=-1;
			t[u].add=0;
            t[u].rnd=rand();
            return u;
        }

        inline int copy(int x)
        {
            int u=++cnt;
            t[u]=t[x];return u;
        }
        
        inline void pushup(int x)
        {
            t[x].siz=t[t[x].lc].siz+t[t[x].rc].siz+1;
            t[x].sum=((t[t[x].lc].sum+t[t[x].rc].sum)%mod+t[x].val)%mod;
        }
        
        inline void push_tag(int x,int k)
        { 
           t[x].add=0;
           t[x].tag=t[x].val=k;
           t[x].sum=1ll*t[x].siz*k%mod;
        }

        inline void push_add(int x,int k)
        {
            t[x].add=(t[x].add+k)%mod;
            t[x].val=(t[x].val+k)%mod;
            t[x].sum=(1ll*t[x].sum+1ll*t[x].siz*k)%mod;
        }

        inline void push_rev(int x)
        {
            swap(t[x].lc,t[x].rc);
            t[x].rev^=1;
        }

        inline void pushdown(int x)
        {
            if(!t[x].rev&&!t[x].add&&t[x].tag==-1) return ;
            if(t[x].lc) t[x].lc=copy(t[x].lc);
            if(t[x].rc) t[x].rc=copy(t[x].rc);
            if(t[x].tag!=-1)
            {
                if(t[x].lc) push_tag(t[x].lc,t[x].tag);
                if(t[x].rc) push_tag(t[x].rc,t[x].tag);
                t[x].tag=-1;
            }
            if(t[x].add)
            {
                if(t[x].lc) push_add(t[x].lc,t[x].add);
                if(t[x].rc) push_add(t[x].rc,t[x].add);
                t[x].add=0;
            }
            if(t[x].rev)
            {
                if(t[x].lc) push_rev(t[x].lc);
                if(t[x].rc) push_rev(t[x].rc);
                t[x].rev=0;
            }
        }

        int merge(int x,int y)
        {
            if(!x||!y) return x|y;
            if(t[x].rnd<t[y].rnd)
            {
                pushdown(x);x=copy(x);
                t[x].rc=merge(t[x].rc,y);
                pushup(x);return x;
            }
            else
            {
                pushdown(y);y=copy(y);
                t[y].lc=merge(x,t[y].lc);
                pushup(y);return y;
            }
        }

        void split(int tmp,int k,int &u,int &v)
        {
            if(!tmp)
            {
                u=0;v=0;
                return ;
            }
            pushdown(tmp);
            if(t[t[tmp].lc].siz<k)
            {
                u=copy(tmp);
                split(t[u].rc,k-t[t[tmp].lc].siz-1,t[u].rc,v);
                pushup(u);
            }
            else
            {
                v=copy(tmp);
                split(t[v].lc,k,u,t[v].lc);
                pushup(v);
            }
        }
        
        inline void modify(int l,int r,int k)
        {
            int x,y,z;
            split(rt,r,x,z);
            split(x,l-1,x,y);
            y=copy(y);
            push_tag(y,k);
            rt=merge(x,merge(y,z));
        }

        inline void update(int l,int r,int k)
        {
            int x,y,z;
            split(rt,r,x,z);
            split(x,l-1,x,y);
            y=copy(y);
            push_add(y,k);
            rt=merge(x,merge(y,z));
        }

        inline void query(int l,int r)
        {
            int x,y,z;
            split(rt,r,x,z);
            split(x,l-1,x,y);
            printf("%d\n",t[y].sum%mod);
            rt=merge(x,merge(y,z));
        }

        inline void paste(int l1,int r1,int l2,int r2)
        {
            int a,b,c,d,e;
            bool flag=false;
            if(l1>l2)
            {
                swap(l1,l2);
                swap(r1,r2);
                flag=true;
            }
            split(rt,r2,d,e);
            split(d,l2-1,c,d);
            split(c,r1,b,c);
            split(b,l1-1,a,b);
            if(flag) b=copy(d);
            else d=copy(b);
            rt=merge(a,merge(b,merge(c,merge(d,e))));
        }

        inline void _swap(int l1,int r1,int l2,int r2)
        {
            int a,b,c,d,e;
            if(l1>l2)
            {
                swap(l1,l2);
                swap(r1,r2);
            }
            split(rt,r2,d,e);
            split(d,l2-1,c,d);
            split(c,r1,b,c);
            split(b,l1-1,a,b);
            rt=merge(a,merge(d,merge(c,merge(b,e))));
        }
        
        inline void reverse(int l,int r)
        {
        	int x,y,z;
        	split(rt,r,x,z);
        	split(x,l-1,x,y);
        	y=copy(y);
        	push_rev(y);
        	rt=merge(x,merge(y,z));
		}

        void dfs(int const &x)
        {
            pushdown(x);
            if(t[x].lc) dfs(t[x].lc);
            tmp[++num]=t[x].val;
            if(t[x].rc) dfs(t[x].rc);
        }
        
        int build(int l,int r)
        {
            if(l>r) return 0;
            int mid=(l+r)>>1;
            int x=new_node(tmp[mid]);
            t[x].lc=build(l,mid-1);
            t[x].rc=build(mid+1,r);
            pushup(x);
            return x;
        }

        inline void rebuild()
        {
            num=0;dfs(rt);cnt=0;
            rt=build(1,num);
        }
        
        void watch()
        {
        	int x,y,z;
        	for(int i=1;i<=n;i++)
        	{
        		split(rt,i,x,z);
        		split(x,i-1,x,y);
        		printf("%d ",t[y].val);
        		rt=merge(x,merge(y,z));
			}
			puts("");
		}

    }
    using namespace fhq_treap;

	void work()
	{
        srand(time(0));
	    int opt,l1,l2,r1,r2,v;
        n=read();m=read();
        for(int i=1;i<=n;i++) tmp[i]=read();
        rt=build(1,n);
        for(int i=1;i<=m;i++)
        {
            opt=read();l1=read();r1=read();
            switch(opt) 
            {
            	case 1:
            	{
            		query(l1,r1);
            		break;
				}
				case 2:
				{
					v=read();
                	modify(l1,r1,v);
					break;
				}
				case 3:
				{
					v=read();
                	update(l1,r1,v);
					break;
				}
				case 4:
				{
					l2=read();r2=read();
                	paste(l1,r1,l2,r2);
					break;
				}
				case 5:
				{
					l2=read();r2=read();
                	_swap(l1,r1,l2,r2);
					break;
				}
				case 6:
				{
					reverse(l1,r1);
					break;
				}
			}
            if(cnt>2000000) rebuild();
            //printf("%d : ",i);watch();
        }
        num=0;dfs(rt);
        for(int i=1;i<=n;i++) printf("%d ",tmp[i]);
	}

}

int main()
{
	zzc::work();
	return 0;
}

posted @ 2021-01-07 13:27  youth518  阅读(65)  评论(0编辑  收藏  举报