题目
题解
题目给了很重要的性质,就是保证询问的[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;
}
标签:CF1625E2,Upgrade,int,sum,t1,括号,Cats,root,bid
From: https://www.cnblogs.com/gmh77/p/18536398