CF1625E2. Cats on the Upgrade

题目

题解

题目给了很重要的性质,就是保证询问的[l,r]是合法括号串(没有的话可能要莫队+二分找?)

假设给出的s串是合法括号序,按照树转括号序的方法逆向转成树,用左括号下标作为树上点的标号

例如 ()(()()) ,则有root-1, root-3, 3-4, 3-6,方法是维护左括号的栈,加入右括号时弹左括号t1,然后用上一个左括号t2向t1连边(无t2则用root连)

这样一个子树代表一个左右括号包起来的合法括号串,一段连续的兄弟代表一个合法括号串

记f[t]表示子树t内(不包括子树)的方案,则显然有 \(f_t=\frac{|son_t|(|son_t|+1)}{2}+\sum_{t_s \in son_t} f_{t_s}\),后者是儿子内的方案,前者补上新增的选整段儿子的方案

发现这个式子就是在点t处维护一个和儿子个数相关的量,然后对子树求和

类推一下,询问[l,r]就是求[l,r]对应那一段兄弟节点的f之和,以及 兄弟个数*(兄弟个数+1)/2
前者是对一些连续子树求和,式子与儿子个数相关,在dfs序上连续;后者是对连续兄弟求和,未删为1删为0,在bfs序上连续

所以建树,然后按dfs序和bfs序分别建线段树or树状数组,单点修改(修改父亲在\(tree_{dfs}\)和自己在\(tree_{bfs}\)的值)区间查询


当s串不是合法括号序时,①加右括号时先判栈是否为空 ②最后用root向栈剩下的左括号连边,这样就可以处理了

例如 ())(() ,连root-1,忽略位置3的右括号,4-5连边后4剩下,最后连root-4

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (int a=b; a<=c; a++)
#define fd(a,b,c) for (int a=b; a>=c; a--)
#define low(x) ((x)&-(x))
#define ll long long
//#define file
using namespace std;

const int N=3e5+10;
int n,Q,T;
vector<int> sont[N];
int sumson[N],fa[N];
int xid[N]; //xid[x]: t
int nodeR[N]; //nodeR[t]: x
int dbg[N],ded[N],dfsid; //t
int bid[N],bfsid; //t
char st[N];
vector<int> d;
int root;

struct tree{
	ll tr[N];
	int n;
	void change(int x,ll s)
	{
		while (x<=n) tr[x]+=s,x+=low(x);
	}
	ll Find(int t)
	{
		ll ans=0;
		if (t<=0) return 0;
		while (t) ans+=tr[t],t-=low(t);
		return ans;
	}
	ll find(int x,int y)
	{
		return Find(y)-Find(x-1);
	}
} trb,trd;

void New(int x,int y)
{
	sont[x].push_back(y);
	++sumson[x];
//	cout<<x<<" "<<y<<endl;
}

void buildtree()
{
	root=0;
	fo(i,1,n)
	if (st[i]=='(')
	d.push_back(i),xid[i]=i;
	else
	if (!d.empty())
	{
		int t=d.back();
		xid[i]=t;
		nodeR[t]=i;
		d.pop_back();
		int tfa=d.empty()?root:d.back();
		New(tfa,t);
	}
	for (auto t:d) New(root,t);
}

void dfs(int Fa,int t)
{
	dbg[t]=++dfsid;
	fa[t]=Fa;
	for (auto tson:sont[t]) dfs(t,tson);
	ded[t]=dfsid;
}
void bfs()
{
	deque<int> d;
	d.push_back(root);
	while (!d.empty())
	{
		int t=d.front();
		d.pop_front();
		bid[t]=++bfsid;
		for (auto tson:sont[t]) d.push_back(tson);
	}
}

void solve()
{
    scanf("%d%d",&n,&Q);
    scanf("%s",st+1);
    
    buildtree();
    dfs(0,root);
    bfs();
    trd.n=dfsid,trb.n=bfsid;
    fo(t,1,n)
    if (dbg[t])
    {
    	ll sum=sont[t].size();
    	trd.change(dbg[t],sum*(sum+1)/2);
    	trb.change(bid[t],1);
	}
    
    for (;Q;--Q)
    {
    	int tp,x,y,t1,t2;
    	ll ans=0,sum=0;
    	
    	scanf("%d%d%d",&tp,&x,&y);
    	t1=xid[x],t2=xid[y];
    	if (tp==1)
    	{
    		trd.change(dbg[fa[t1]],-sumson[fa[t1]]);
    		trb.change(bid[t1],-1);
    		--sumson[fa[t1]];
		}
		else
		{
			sum=trb.find(bid[t1],bid[t2]);
			ans=trd.find(dbg[t1],ded[t2])+sum*(sum+1)/2;
			printf("%lld\n",ans);
		}
	}
}

int main()
{
//	freopen("CF1625E.in","r",stdin);
	#ifdef file
	freopen("a.out","w",stdout);
	#endif

    T=1;
    //scanf("%d",&T);
    for (;T;--T) solve();

    return 0;
}
posted @ 2024-11-09 10:27  gmh77  阅读(3)  评论(0编辑  收藏  举报