zoukankan      html  css  js  c++  java
  • 【模板】文艺平衡树-BZOJ3223

    Description

      您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1

    Input

      第一行为n,m,n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数
      接下来m行每行两个数[L,R] 数据保证 1<=L<=R<=n

    Output

      输出一行n个数字,表示原始序列经过m次变换后的结果

    Sample Input

    5 3
    1 3
    1 3
    1 4

    Sample Output

    4 3 2 1 5

    Hint

    【数据范围】1≤n,m≤100000


    思路

    • 初始加入哨兵(table最大最小值防止边界溢出)
    • 因初始从1~n有序,找到树中排名第i,i+1的数,第i个数val[i+1]满足:val[i]<val[i+1]<val[n+2]
    • 亲测初始向树中增加数字用普通平衡树操作insert函数答案正确但会超时(详见附录1),技巧:题目权值有序1~Ninsert的一个优化
    • 翻转只需在根节点的地方打一个标记
    • 因为标记下放易错,我统一采取得到标记就翻转的模式
    • 输出的时候输出的就是Splay的中序遍历

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define maxn 100005
    #define inf 0x7fffffff
    using namespace std;
    int n,m;
    int val[maxn],num[maxn],fa[maxn],ch[maxn][3],siz[maxn],id[maxn],flag[maxn],cnt,root,neww;
    void pushup(int x){siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+num[x];}
    void pushdown(int x)
    {
    	if(flag[x])
    	{
    		if(ch[x][0]){flag[ch[x][0]]^=1; swap(ch[ch[x][0]][0],ch[ch[x][0]][1]);}
    		if(ch[x][1]){flag[ch[x][1]]^=1; swap(ch[ch[x][1]][0],ch[ch[x][1]][1]);}
    		flag[x]=0;
    	}
    }
    void table()
    {
    	fa[n+2]=1; ch[1][0]=n+2;
    	val[n+2]=-inf; val[1]=inf;
    	siz[1]=2; siz[n+2]=1; num[n+2]=num[1]=1;
    	cnt=1; root=1;
    }
    void rot(int x,int &f)
    {
    	int y=fa[x],z=fa[y],l=(ch[y][0]!=x),r=(l^1);
    	if(y==f) f=x;
    	else if(ch[z][0]==y) ch[z][0]=x;
    	else ch[z][1]=x;
    	fa[x]=z; fa[y]=x; fa[ch[x][r]]=y;
    	ch[y][l]=ch[x][r]; ch[x][r]=y;
    	pushup(y); pushup(x);
    }
    void splay(int x,int &f)
    {
    	while(x!=f)
    	{
    		int y=fa[x],z=fa[y];
    		if(y!=f){if(ch[z][0]==y^ch[y][0]==x) rot(x,f);else rot(y,f);}
    		rot(x,f);
    	}
    }
    int findk(int x,int rt)
    {
    	pushdown(rt);
    	if(siz[ch[rt][0]]+num[rt]>=x&&siz[ch[rt][0]]<x) return rt;
    	else if(siz[ch[rt][0]]>=x) return findk(x,ch[rt][0]);
    	else return findk(x-siz[ch[rt][0]]-num[rt],ch[rt][1]);
    }
    void dfs(int rt)
    {
    	pushdown(rt);
    	if(ch[rt][0]) dfs(ch[rt][0]);
    	if(val[rt]!=inf&&val[rt]!=-inf) printf("%d ",val[rt]);
    	if(ch[rt][1]) dfs(ch[rt][1]);
    }
    int main()
    {
    	scanf("%d%d",&n,&m); table();
    	for(int i=1;i<=n;++i)
    	{
    		int a=findk(i,root),b=findk(i+1,root);
    		splay(a,root),splay(b,ch[root][1]);
    		ch[b][0]=++cnt; val[cnt]=i; num[cnt]=siz[cnt]=1; fa[cnt]=b;
    	}
    	cnt=n+2;
    	while(m--)
    	{
    		int f1,f2; scanf("%d%d",&f1,&f2);
    		f1=findk(f1,root); f2=findk(f2+2,root);	splay(f1,root); splay(f2,ch[root][1]);
    		flag[ch[ch[root][1]][0]]^=1;
    		swap(ch[ch[ch[root][1]][0]][1],ch[ch[ch[root][1]][0]][0]);
    	}
    	dfs(root);
    	return 0;
    }
    

    附录1

    • 超时代码:
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define maxn 100005
    #define inf 0x7fffffff
    using namespace std;
    int n,m;
    int val[maxn],num[maxn],fa[maxn],ch[maxn][3],siz[maxn],id[maxn],flag[maxn],cnt,root,neww;
    void pushup(int x){siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+num[x];}
    void pushdown(int x)
    {
    	if(flag[x])
    	{
    		if(ch[x][0]){flag[ch[x][0]]^=1; swap(ch[ch[x][0]][0],ch[ch[x][0]][1]);}
    		if(ch[x][1]){flag[ch[x][1]]^=1; swap(ch[ch[x][1]][0],ch[ch[x][1]][1]);}
    		flag[x]=0;
    	}
    }
    void table()
    {
    	fa[n+2]=1; ch[1][0]=n+2;
    	val[n+2]=-inf; val[1]=inf;
    	siz[1]=2; siz[n+2]=1; num[n+2]=num[1]=1;
    	cnt=1; root=1;
    }
    void rot(int x,int &f)
    {
    	int y=fa[x],z=fa[y],l=(ch[y][0]!=x),r=(l^1);
    	if(y==f) f=x;
    	else if(ch[z][0]==y) ch[z][0]=x;
    	else ch[z][1]=x;
    	fa[x]=z; fa[y]=x; fa[ch[x][r]]=y;
    	ch[y][l]=ch[x][r]; ch[x][r]=y;
    	pushup(y); pushup(x);
    }
    void splay(int x,int &f)
    {
    	while(x!=f)
    	{
    		int y=fa[x],z=fa[y];
    		if(y!=f){if(ch[z][0]==y^ch[y][0]==x) rot(x,f);else rot(y,f);}
    		rot(x,f);
    	}
    }
    int findk(int x,int rt)
    {
    	pushdown(rt);
    	if(siz[ch[rt][0]]+num[rt]>=x&&siz[ch[rt][0]]<x) return rt;
    	else if(siz[ch[rt][0]]>=x) return findk(x,ch[rt][0]);
    	else return findk(x-siz[ch[rt][0]]-num[rt],ch[rt][1]);
    }
    void dfs(int rt)
    {
    	pushdown(rt);
    	if(ch[rt][0]) dfs(ch[rt][0]);
    	if(val[rt]!=inf&&val[rt]!=-inf) printf("%d ",val[rt]);
    	if(ch[rt][1]) dfs(ch[rt][1]);
    }
    void insert(int x,int rt)
    {
    	if(val[rt]>x&&ch[rt][0]) insert(x,ch[rt][0]);
    	else if(val[rt]<x&&ch[rt][1]) insert(x,ch[rt][1]);
    	else if(val[rt]==x) num[rt]++,siz[rt]++,neww=rt;
    	else
    	{
    		if(val[rt]>x) ch[rt][0]=++cnt;
    		else if(val[rt]<x) ch[rt][1]=++cnt;
    		fa[cnt]=rt; siz[cnt]=1; val[cnt]=x; num[cnt]=1; neww=cnt;
    	}
    	pushup(rt);
    }
    int main()
    {
    	scanf("%d%d",&n,&m); table();
    	for(int i=1;i<=n;++i) insert(i,root);
    /*	{
    		int a=findk(i,root),b=findk(i+1,root);
    		splay(a,root),splay(b,ch[root][1]);
    		ch[b][0]=++cnt; val[cnt]=i; num[cnt]=siz[cnt]=1; fa[cnt]=b;
    	}*/
    	cnt=n+2;
    	while(m--)
    	{
    		int f1,f2; scanf("%d%d",&f1,&f2);
    		f1=findk(f1,root); f2=findk(f2+2,root);	splay(f1,root); splay(f2,ch[root][1]);
    		flag[ch[ch[root][1]][0]]^=1;
    		swap(ch[ch[ch[root][1]][0]][1],ch[ch[ch[root][1]][0]][0]);
    	}
    	dfs(root);
    	return 0;
    }
    
  • 相关阅读:
    Opencv 图像矩
    Opencv Convex Hull (凸包)
    Opencv 发现轮廓 findContours
    Opencv Match Template(轮廓匹配)
    python操作mysql数据库的常用方法使用详解
    mongodb数据库集群及sharding分片配置
    mongodb数据库安装及常见操作
    windows下搭建eclipse关于python的开发环境及初始化参数配置
    python环境下使用tab自动补全命令
    ubuntu系统初始化网络及mysql配置
  • 原文地址:https://www.cnblogs.com/wuwendongxi/p/13445930.html
Copyright © 2011-2022 走看看