Repair the brckets FZU1987


这道题的关键就是知道一个修复一个括号序列的最小改变数

把'('变成1,')'变成-1,lmi为左起最小连续子段和(可以为空),sum为序列的和,则答案为(lim+1)/2+(sum-lmi+1)/2

简单想了想,设i为lmi的结束下标,则有[1, i]所有的'('全部被匹配,[i+1, n]全部的‘)’都被匹配,如果不满足这个性质的话,则lmi还可以更小,这与假设相矛盾,所以-lmi就是[1,i]中没有被匹配的')'个数,而sum-lmi就是[i+1, n]没有被匹配的'('个数,所以只要分别修改[1,i]中的')'和[i+1]中的'('即可,由于原序列长度为偶数,所以|lmi|+|sum-lmi|一定是偶数,但

|lmi|和|sum-lmi|不一定是偶数,对于这种情况需要吧[1,i]中最后一个未匹配')'变为'(',[i+1,n]第一个未匹配'('变为')',而|lmi|-1和|sum-lmi|-1又变成了偶数,综合这两种情况就可以得到上面的式子

剩下的就是splay的各种鬼畜操作了

这种单纯考察数据结构的题我都要调试N多遍才能通过,看来代码能力还是需要加强额


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;

const int MAXN(50010);
const int MAXM(10010);
const int MAXE(10010);
const int MAXH(19);
const int INFI((INT_MAX-1) >> 1);
const int MOD(10000);
const ULL BASE(31);
const LL LIM(10000000);
const int INV(-10000);


int arr[MAXN];

struct SPLAY_TREE
{
	struct NODE
	{
		int num, size, flag1, flag2, flag3;  //replace标记,reverse标记,inverse标记
		int sum, lmi, rmi, lmx, rmx;  //总和,左起连续最小和,右起连续最小和,左起连续最大和,右起连续最大和
		NODE *fa;
		NODE *ch[2];
	};

	NODE pool[MAXN];
	NODE *root, *NIL, *rear;
	inline void push_up(NODE *sour)  //一定要注意NIL节点对push_up的影响
	{
		sour->size = sour->ch[0]->size+sour->ch[1]->size+1;
		sour->sum = sour->ch[0]->sum+sour->ch[1]->sum+sour->num;
		sour->lmi = min(sour->ch[0]->lmi, sour->ch[0]->sum+sour->num+sour->ch[1]->lmi);
		sour->rmi = min(sour->ch[1]->rmi, sour->ch[1]->sum+sour->num+sour->ch[0]->rmi);
		sour->lmx = max(sour->ch[0]->lmx, sour->ch[0]->sum+sour->num+sour->ch[1]->lmx);
		sour->rmx = max(sour->ch[1]->rmx, sour->ch[1]->sum+sour->num+sour->ch[0]->rmx);
	}
	inline void updata_rep(NODE *sour, int v)
	{
		if(sour == NIL) return;
		sour->num = v;
		sour->sum = v*sour->size;
		sour->rmi = sour->lmi = v > 0? 0: v*sour->size;
		sour->lmx = sour->rmx = v > 0? v*sour->size: 0;
		sour->flag1 = v;
		sour->flag2 = 0;
		sour->flag3 = 0;
	}
	inline void updata_rev(NODE *sour)
	{
		if(sour == NIL) return;
		swap(sour->ch[0], sour->ch[1]);
		swap(sour->lmi, sour->rmi);
		swap(sour->lmx, sour->rmx);
		sour->flag2 ^= 1;
	}
	inline void updata_inv(NODE *sour)
	{
		if(sour == NIL) return;
		int temp = sour->lmi;
		swap(sour->lmi, sour->lmx);
		swap(sour->rmi, sour->rmx);
		sour->lmi *= -1;
		sour->lmx *= -1;
		sour->rmi *= -1;
		sour->rmx *= -1;
		sour->num *= -1;
		sour->sum *= -1;
		if(sour->flag1)
			sour->flag1 *= -1;
		else
			sour->flag3 ^= 1;
	}
	void push_down(NODE *sour)  //和线段树的push_down一样,是对子节(注意不是本节点)进行更新
	{
		if(sour->flag1)
		{
			updata_rep(sour->ch[0], sour->flag1);
			updata_rep(sour->ch[1], sour->flag1);
			sour->flag1 = 0;
		}
		if(sour->flag2)
		{
			updata_rev(sour->ch[0]);
			updata_rev(sour->ch[1]);
			sour->flag2 = 0;
		}
		if(sour->flag3)
		{
			updata_inv(sour->ch[0]);
			updata_inv(sour->ch[1]);
			sour->flag3 = 0;
		}
	}
	void initNIL()
	{
		NIL->ch[0] = NIL->ch[1] = NIL->fa = NIL;
		NIL->lmi = NIL->rmi = NIL->lmx = NIL->rmx = NIL->sum = NIL->num = 0;
		NIL->size = 0;
	}

	void init(int n)
	{
		NIL = pool;
		initNIL();
		rear = pool+1;
		newnode(root, NIL, -100000);  //插入无穷小
		newnode(root->ch[1], root, 100000); //插入无穷大
		build_tree(root->ch[1]->ch[0], root->ch[1], 1, n); //建树
		push_up(root->ch[1]);
		push_up(root);
	}

	void newnode(NODE *&sour, NODE *f, int num)
	{
		sour = rear++;
		sour->num = sour->sum = num;
		sour->size = 1;
		sour->lmi = sour->rmi = num > 0? 0: num;
		sour->lmx = sour->rmx = num > 0? num: 0;
		sour->flag1 = sour->flag2 = sour->flag3 = 0;
		sour->fa = f;
		sour->ch[0] = sour->ch[1] = NIL;
	}

	void build_tree(NODE *&sour, NODE *f, int l, int r)
	{
		if(l > r)
			return;
		int m = (l+r) >> 1;
		newnode(sour, f, arr[m]);
		build_tree(sour->ch[0], sour, l, m-1);
		build_tree(sour->ch[1], sour, m+1, r);
		push_up(sour);
	}

	void rotate(NODE *sour, int flag)
	{
		NODE *f = sour->fa;
		push_down(f);
		push_down(sour);
		f->ch[!flag] = sour->ch[flag];
		sour->ch[flag]->fa = f;
		sour->fa = f->fa;
		if(f->fa != NIL)
			f->fa->ch[f->fa->ch[1] == f] = sour;
		sour->ch[flag] = f;
		f->fa = sour;
		push_up(f);
	}
	
	void splay(NODE *sour, NODE *goal)
	{
		push_down(sour);
		while(sour->fa != goal)
		{
			if(sour->fa->fa == goal)
				rotate(sour, sour->fa->ch[0] == sour);
			else
			{
				NODE *f = sour->fa;
				int flag = (f->fa->ch[0] == f);
				if(f->ch[flag] == sour)
					rotate(sour, !flag);
				else
					rotate(f, flag);
				rotate(sour, flag);
			}
		}
		push_up(sour);
		if(goal == NIL)
			root = sour;
	}

	NODE *select(NODE *sour, int r)
	{
		while(sour != NIL)
		{
			push_down(sour);
			if(r == sour->ch[0]->size+1)
				break;
			if(r <= sour->ch[0]->size)
				sour = sour->ch[0];
			else
			{
				r -= sour->ch[0]->size+1;
				sour = sour->ch[1];
			}
		}
		return sour;
	}
	inline void pick(int pos1, int pos2)
	{
		NODE *tp = select(root, pos1);
		splay(tp, NIL);
		tp = select(root, pos2+2);
		splay(tp, root);
	}
	void REPLACE(int pos1, int pos2, int value)
	{
		pick(pos1, pos2);
		updata_rep(root->ch[1]->ch[0], value);
		push_up(root->ch[1]);
		push_up(root);
	}

	void SWAP(int pos1, int pos2)
	{
		pick(pos1, pos2);
		updata_rev(root->ch[1]->ch[0]);
		push_up(root->ch[1]);
		push_up(root);
	}

	void INVERT(int pos1, int pos2)
	{
		pick(pos1, pos2);
		updata_inv(root->ch[1]->ch[0]);
		push_up(root->ch[1]);
		push_up(root);
	}

	int QUERY(int pos1, int pos2)
	{
		pick(pos1, pos2);
		NODE *tp = root->ch[1]->ch[0];
		return (abs(tp->sum-tp->lmi)+1)/2+(abs(tp->lmi)+1)/2;
	}
};

SPLAY_TREE spt;
char str[10];
int op1, op2;
char op3;

int main()
{
	int TC, n_case(0);
	scanf("%d", &TC);
	while(TC--)
	{
		int n, m;
		scanf("%d%d", &n, &m);
		char temp;
		for(int i = 1; i <= n; ++i)
		{
			scanf(" %c", &temp);
			arr[i] = temp == '('? 1: -1;
		}
		spt.init(n);
		printf("Case %d:\n", ++n_case);
		for(int i = 0; i < m; ++i)
		{
			scanf("%s", str);
			if(str[0] == 'R')
			{
				scanf("%d%d %c", &op1, &op2, &op3);
				spt.REPLACE(op1, op2, op3 == '('? 1: -1);
			}
			else if(str[0] == 'S')
			{
				scanf("%d%d", &op1, &op2);
				spt.SWAP(op1, op2);
			}
			else if(str[0] == 'I')
			{
				scanf("%d%d", &op1, &op2);
				spt.INVERT(op1, op2);
			}
			else
			{
				scanf("%d%d", &op1, &op2);
				printf("%d\n", spt.QUERY(op1, op2));
			}
		}
	}
	return 0;
}

又想了想,lmx和rmx是不必要维护的


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;

const int MAXN(50010);
const int MAXM(10010);
const int MAXE(10010);
const int MAXH(19);
const int INFI((INT_MAX-1) >> 1);
const int MOD(10000);
const ULL BASE(31);
const LL LIM(10000000);
const int INV(-10000);


int arr[MAXN];

struct SPLAY_TREE
{
	struct NODE
	{
		int num, size, flag1, flag2, flag3;  
		int sum, lmi, rmi;                   //区域和 ,左起连续最小和(可以0个元素), 右起连续最小和(可以0个元素)
		NODE *fa;
		NODE *ch[2];
	};

	NODE pool[MAXN];
	NODE *root, *NIL, *rear;
	inline void push_up(NODE *sour)  //一定要注意NIL节点对push_up的影响
	{
		sour->size = sour->ch[0]->size+sour->ch[1]->size+1;
		sour->sum = sour->ch[0]->sum+sour->ch[1]->sum+sour->num;
		sour->lmi = min(sour->ch[0]->lmi, sour->ch[0]->sum+sour->num+sour->ch[1]->lmi);
		sour->rmi = min(sour->ch[1]->rmi, sour->ch[1]->sum+sour->num+sour->ch[0]->rmi);
	}
	inline void updata_rep(NODE *sour, int v)
	{
		if(sour == NIL) return;
		sour->num = v;
		sour->sum = v*sour->size;
		sour->rmi = sour->lmi = v > 0? 0: v*sour->size;
		sour->flag1 = v;
		sour->flag2 = 0;
		sour->flag3 = 0;
	}
	inline void updata_rev(NODE *sour)
	{
		if(sour == NIL) return;
		swap(sour->ch[0], sour->ch[1]);
		swap(sour->lmi, sour->rmi);
		sour->flag2 ^= 1;
	}
	inline void updata_inv(NODE *sour)
	{
		if(sour == NIL) return;
		int temp = sour->lmi;
		sour->lmi = -(sour->sum-sour->rmi);
		sour->rmi = -(sour->sum-temp);
		sour->sum *= -1;
		sour->num *= -1;
		if(sour->flag1)
			sour->flag1 *= -1;
		else
			sour->flag3 ^= 1;
	}
	void push_down(NODE *sour)  //和线段树的push_down一样,是对子节(注意不是本节点)进行更新
	{
		if(sour->flag1)
		{
			updata_rep(sour->ch[0], sour->flag1);
			updata_rep(sour->ch[1], sour->flag1);
			sour->flag1 = 0;
		}
		if(sour->flag2)
		{
			updata_rev(sour->ch[0]);
			updata_rev(sour->ch[1]);
			sour->flag2 = 0;
		}
		if(sour->flag3)
		{
			updata_inv(sour->ch[0]);
			updata_inv(sour->ch[1]);
			sour->flag3 = 0;
		}
	}
	void initNIL()
	{
		NIL->ch[0] = NIL->ch[1] = NIL->fa = NIL;
		NIL->lmi = NIL->rmi = NIL->sum = NIL->num = 0; 
		NIL->size = 0;
	}

	void init(int n)
	{
		NIL = pool;
		initNIL();
		rear = pool+1;
		newnode(root, NIL, -100000);  //插入无穷小
		newnode(root->ch[1], root, 100000); //插入无穷大
		build_tree(root->ch[1]->ch[0], root->ch[1], 1, n); //建树
		push_up(root->ch[1]);
		push_up(root);
	}

	void newnode(NODE *&sour, NODE *f, int num)
	{
		sour = rear++;
		sour->num = sour->sum = num;
		sour->size = 1;
		sour->lmi = sour->rmi = num > 0? 0: num;
		sour->flag1 = sour->flag2 = sour->flag3 = 0;
		sour->fa = f;
		sour->ch[0] = sour->ch[1] = NIL;
	}

	void build_tree(NODE *&sour, NODE *f, int l, int r)
	{
		if(l > r)
			return;
		int m = (l+r) >> 1;
		newnode(sour, f, arr[m]);
		build_tree(sour->ch[0], sour, l, m-1);
		build_tree(sour->ch[1], sour, m+1, r);
		push_up(sour);
	}

	void rotate(NODE *sour, int flag)
	{
		NODE *f = sour->fa;
		push_down(f);
		push_down(sour);
		f->ch[!flag] = sour->ch[flag];
		sour->ch[flag]->fa = f;
		sour->fa = f->fa;
		if(f->fa != NIL)
			f->fa->ch[f->fa->ch[1] == f] = sour;
		sour->ch[flag] = f;
		f->fa = sour;
		push_up(f);
	}
	
	void splay(NODE *sour, NODE *goal)
	{
		push_down(sour);
		while(sour->fa != goal)
		{
			if(sour->fa->fa == goal)
				rotate(sour, sour->fa->ch[0] == sour);
			else
			{
				NODE *f = sour->fa;
				int flag = (f->fa->ch[0] == f);
				if(f->ch[flag] == sour)
					rotate(sour, !flag);
				else
					rotate(f, flag);
				rotate(sour, flag);
			}
		}
		push_up(sour);
		if(goal == NIL)
			root = sour;
	}

	NODE *select(NODE *sour, int r)
	{
		while(sour != NIL)
		{
			push_down(sour);
			if(r == sour->ch[0]->size+1)
				break;
			if(r <= sour->ch[0]->size)
				sour = sour->ch[0];
			else
			{
				r -= sour->ch[0]->size+1;
				sour = sour->ch[1];
			}
		}
		return sour;
	}
	inline void pick(int pos1, int pos2)
	{
		NODE *tp = select(root, pos1);
		splay(tp, NIL);
		tp = select(root, pos2+2);
		splay(tp, root);
	}
	void REPLACE(int pos1, int pos2, int value)
	{
		pick(pos1, pos2);
		updata_rep(root->ch[1]->ch[0], value);
		push_up(root->ch[1]);
		push_up(root);
	}

	void SWAP(int pos1, int pos2)
	{
		pick(pos1, pos2);
		updata_rev(root->ch[1]->ch[0]);
		push_up(root->ch[1]);
		push_up(root);
	}

	void INVERT(int pos1, int pos2)
	{
		pick(pos1, pos2);
		updata_inv(root->ch[1]->ch[0]);
		push_up(root->ch[1]);
		push_up(root);
	}

	int QUERY(int pos1, int pos2)
	{
		pick(pos1, pos2);
		NODE *tp = root->ch[1]->ch[0];
		return (abs(tp->sum-tp->lmi)+1)/2+(abs(tp->lmi)+1)/2;
	}
};

SPLAY_TREE spt;
char str[10];
int op1, op2;
char op3;

int main()
{
	int TC, n_case(0);
	scanf("%d", &TC);
	while(TC--)
	{
		int n, m;
		scanf("%d%d", &n, &m);
		char temp;
		for(int i = 1; i <= n; ++i)
		{
			scanf(" %c", &temp);
			arr[i] = temp == '('? 1: -1;
		}
		spt.init(n);
		printf("Case %d:\n", ++n_case);
		for(int i = 0; i < m; ++i)
		{
			scanf("%s", str);
			if(str[0] == 'R')
			{
				scanf("%d%d %c", &op1, &op2, &op3);
				spt.REPLACE(op1, op2, op3 == '('? 1: -1);
			}
			else if(str[0] == 'S')
			{
				scanf("%d%d", &op1, &op2);
				spt.SWAP(op1, op2);
			}
			else if(str[0] == 'I')
			{
				scanf("%d%d", &op1, &op2);
				spt.INVERT(op1, op2);
			}
			else
			{
				scanf("%d%d", &op1, &op2);
				printf("%d\n", spt.QUERY(op1, op2));
			}
		}
	}
	return 0;
}




你可能感兴趣的:(Repair the brckets FZU1987)