P3391 【模板】文藝平衡樹

liuboom發表於2024-12-06

P3391 【模板】文藝平衡樹

【模板】文藝平衡樹

題目描述

您需要寫一種資料結構(可參考題目標題),來維護一個有序數列。

其中需要提供以下操作:翻轉一個區間。

輸入格式

第一行兩個正整數 \(n,m\),表示序列長度與操作個數。序列中第 \(i\) 項初始為 \(i\)
接下來 \(m\) 行,每行兩個正整數 \(l,r\),表示翻轉的區間。

輸出格式

輸出一行 \(n\) 個正整數,表示原始序列經過 \(m\) 次變換後的結果。

【資料範圍】
對於 \(100\%\) 的資料,$1 \le n, m \leq 100000 $,\(1 \le l \le r \le n\)

感覺和模板平衡樹很像,唯一的區別就是這題不用按點權分裂,而是直接按節點個數分裂

每次交換操作就直接給區間打tag,然後交換左右兒子
最後統計的時候直接中序dfs就好了

Code:

#include<bits/stdc++.h>
#include<ctime>
const int N=1e5+5;
using namespace std;
struct Tree{
	int val,tag,siz,pri,ls,rs;
}t[N<<2];
int n,m,cnt,rt;
int new_(int w=0)
{
	int x=++cnt;
	t[x].val=w,t[x].siz=1,t[x].pri=rand();
	return x;
}
void upd(int x)
{
	t[x].siz=t[t[x].ls].siz+t[t[x].rs].siz+1;
}
void pushdown(int x)
{
	if(!t[x].tag)return ;
	t[x].tag=0;
	t[t[x].ls].tag^=1;
	t[t[x].rs].tag^=1;
	swap(t[x].ls,t[x].rs);
	return ;
}
void split(int x,int k,int &a,int &b)
{
	if(!x){a=b=0;return;}
	pushdown(x);
	if(k<=t[t[x].ls].siz)
	{
		b=x;
		split(t[b].ls,k,a,t[b].ls);
		upd(b);
	}
	else
	{
		a=x;k-=(t[t[x].ls].siz+1);
		split(t[a].rs,k,t[a].rs,b);
		upd(a);
	}
}
int merge(int x,int y)
{
	if(!x||!y)return x+y;
	if(t[x].pri<t[y].pri)
	{
		pushdown(x);
		t[x].rs=merge(t[x].rs,y);
		upd(x);
		return x;
	}
	else
	{
		pushdown(y);
		t[y].ls=merge(x,t[y].ls);
		upd(y);
		return y;
	}
}
queue<int> Q;
void calc(int x)
{
	if(!x)return ;
	pushdown(x);
	calc(t[x].ls);
	Q.push(t[x].val);
	calc(t[x].rs);
}
void work()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		rt=merge(rt,new_(i));
	}
	for(int i=1,l,r;i<=m;i++)
	{
		scanf("%d%d",&l,&r);
		int a=0,b=0,c=0;
		split(rt,l-1,a,b);//a[1,l-1] : b[l,n]
		split(b,r-l+1,b,c);//b[l,r] : c[r+1,n]
		//cout<<"val:"<<t[a].val<<" "<<t[b].val<<" "<<t[c].val<<"\n";
		//cout<<"siz:"<<t[a].siz<<" "<<t[b].siz<<" "<<t[c].siz<<"\n";
		t[b].tag^=1;
		rt=merge(merge(a,b),c);
	}
	calc(rt);
	while(!Q.empty())
	{
		printf("%d ",Q.front());
		Q.pop();
	}
}
int main()
{
	//freopen("P3391.in","r",stdin);
	srand(clock());
	work();
}

相關文章