平衡树题

P4036 [JSOI2008] 火星人

用平衡树维护:

在位置 \(x\) 后插入一个字符。

修改位置 \(x\) 的字符。

查询区间公共前缀长度可用 hash 维护前缀,二分长度,判断 hash 值是否相等。

P3215 [HNOI2011] 括号修复 / [JSOI2011] 括号序列

lxl 大佬做法。

先看查询操作,对于任意序列 ))()()((,其中已经匹配成功的不需要改,剩下的为 ))((,发现序列长度为偶数时,隔一个改一个,只需改 \((a+b)/2\) 个,长度为奇数时还需额外改一个答案为 \((a+b)/2+1\)

\(a\) 为左边右括号数量,\(b\)为右边左括号数量。

一操作:区间覆盖,一个长度为 \(len\) 的序列全部修改为右括号,那 \(a=0,b=len\)

二操作:区间翻转,因为维护的状态只有翻转和没翻转两种状态,可以同时维护这两个状态,在进行区间翻转操作时交换值。

三操作:区间反转,同样道理也不断维护反转和没反转的状态。

可以想到要先区间反转,再区间翻转,再区间覆盖。

https://www.cnblogs.com/laijinyi/p/18449771

#include <bits/stdc++.h>
#define ll long long
#define int ll
#define ls a[p].l
#define rs a[p].r 
#define re register 
#define pb push_back
#define pir pair<int,int>
#define f(a,x,i) for(int i=a;i<=x;i++)
#define fr(a,x,i) for(int i=a;i>=x;i--)
#define lb(x) x&(-x); 
using namespace std;
const int N=2e5+10;
const int M=8e6+10;
const int mod=1e9+7;
mt19937 rnd(251);

int n=0;
int root=0;
struct node{
	int l,r;
	int siz;
	int rnd;
	int tag1;//覆盖
	int tag2;//翻转
	int tag3;//反转
	
	int v1,v2;//该点类型
	int vi1,vi2;//反转

	int x1,z1;//未动
	int x2,z2;//翻转后
	int x3,z3;//反转后
	int x4,z4;//反转翻转后
}a[N];

void swp(int y){
	swap(a[y].x1,a[y].x2);
	swap(a[y].z1,a[y].z2);

	swap(a[y].x3,a[y].x4);
	swap(a[y].z3,a[y].z4);

	swap(a[y].l,a[y].r);
	a[y].tag2^=1;
}

void replace(int y,int k){
	a[y].tag1=k;a[y].tag3=0;

	if(k==1){
		a[y].v1=1;
		a[y].vi2=1;
		a[y].x1=a[y].siz;
		a[y].x2=a[y].siz;
		a[y].z3=a[y].siz;
		a[y].z4=a[y].siz;

		a[y].v2=0;
		a[y].vi1=0;
		a[y].z1=0;
		a[y].z2=0;
		a[y].x3=0;
		a[y].x4=0;
	}
	else{
		a[y].v1=0;
		a[y].vi2=0;
		a[y].x1=0;
		a[y].x2=0;
		a[y].z3=0;
		a[y].z4=0;

		a[y].v2=1;
		a[y].vi1=1;
		a[y].z1=a[y].siz;
		a[y].z2=a[y].siz;
		a[y].x3=a[y].siz;
		a[y].x4=a[y].siz;
	}
}

void invert(int y){
	swap(a[y].x1,a[y].x3);
	swap(a[y].z1,a[y].z3);
	
	swap(a[y].x2,a[y].x4);
	swap(a[y].z2,a[y].z4);

	swap(a[y].v1,a[y].vi1);
	swap(a[y].v2,a[y].vi2);
	a[y].tag3^=1;
}

void pushdown(int p){
	if(a[p].tag1){
		replace(ls,a[p].tag1);
		replace(rs,a[p].tag1);
		a[p].tag1=0;
	}
	if(a[p].tag2){
		swp(ls);
		swp(rs);
		a[p].tag2=0;
	}
	if(a[p].tag3){
		invert(ls);
		invert(rs);
		a[p].tag3=0;
	}
}

void pushup(int p){
	a[p].siz=a[ls].siz+a[rs].siz+1;

	a[p].x1=a[ls].x1+max(0ll,a[p].v1-a[ls].z1);
	a[p].z1=a[p].v2+max(0ll,a[ls].z1-a[p].v1);

	a[p].x1=a[p].x1+max(0ll,a[rs].x1-a[p].z1);
	a[p].z1=a[rs].z1+max(0ll,a[p].z1-a[rs].x1);


	a[p].x3=a[ls].x3+max(0ll,a[p].vi1-a[ls].z3);
	a[p].z3=a[p].vi2+max(0ll,a[ls].z3-a[p].vi1);

	a[p].x3=a[p].x3+max(0ll,a[rs].x3-a[p].z3);
	a[p].z3=a[rs].z3+max(0ll,a[p].z3-a[rs].x3);

	a[p].x2=a[rs].x2+max(0ll,a[p].v1-a[rs].z2);
	a[p].z2=a[p].v2+max(0ll,a[rs].z2-a[p].v1);

	a[p].x2=a[p].x2+max(0ll,a[ls].x2-a[p].z2);
	a[p].z2=a[ls].z2+max(0ll,a[p].z2-a[ls].x2);

	a[p].x4=a[rs].x4+max(0ll,a[p].vi1-a[rs].z4);
	a[p].z4=a[p].vi2+max(0ll,a[rs].z4-a[p].vi1);

	a[p].x4=a[p].x4+max(0ll,a[ls].x4-a[p].z4);
	a[p].z4=a[ls].z4+max(0ll,a[p].z4-a[ls].x4);
}

void split(int p,int k,int &x,int &y){
	if(!p){
		x=y=0;
		return;
	}
	pushdown(p);
	if(a[ls].siz<k){
		x=p;
		k-=a[ls].siz+1;
		split(rs,k,rs,y);
	}
	else{
		y=p;
		split(ls,k,x,ls);
	}
	pushup(p);
}

int merge(int x,int y){
	if(!x||!y){
		return x|y;
	}
	pushdown(x);
	pushdown(y);
	if(a[x].rnd<a[y].rnd){
		a[x].r=merge(a[x].r,y);
		pushup(x);
		return x;
	}
	else{
		a[y].l=merge(x,a[y].l);
		pushup(y);
		return y;
	}
}

int newnode(int v){
	a[++n].rnd=rnd();
	a[n].siz=1;
	if(v==1){
		a[n].v1=1;
		a[n].vi2=1;
		a[n].x1=1;
		a[n].x2=1;
		a[n].z3=1;
		a[n].z4=1;
	}
	else{
		a[n].v2=1;
		a[n].vi1=1;
		a[n].z1=1;
		a[n].z2=1;
		a[n].x3=1;
		a[n].x4=1;
	}
	return n;
}

int F(int x){
	return x / 2 + (x % 2 == 1);
}

signed main(){
	// freopen("a.in","r",stdin);
    ios::sync_with_stdio(0);
    cin.tie(nullptr);   
	int len,m;
	string s;
	cin>>len>>m>>s;
	for(int i=0;i<len;i++){
		int k=2;
		if(s[i]==')'){
			k=1;
		}
		root=merge(root,newnode(k));
	}

	for(int i=1;i<=m;i++){
		int l,r;
		string op;
		cin>>op>>l>>r;
		
		int x,y,z;
		split(root,l-1,x,y);
		split(y,r-l+1,y,z);

		if(op[0]=='Q'){
			cout<<F(a[y].x1)+F(a[y].z1)<<"\n";
		}
		else if(op[0]=='R'){
			char c;
			cin>>c;
			int k=2;
			if(c==')'){
				k=1;
			}
			replace(y,k);
		}
		else if(op[0]=='I'){
			invert(y);
		}
		else{
			swp(y);
		}
		root=merge(merge(x,y),z);
	}
    return 0;
}
posted @ 2025-02-03 22:55  sad_lin  阅读(15)  评论(0)    收藏  举报