當前位置:
首頁 >
jzoj4273-圣章-精灵使的魔法语【线段树】
發布時間:2023/12/3
39
豆豆
默认站点
收集整理的這篇文章主要介紹了
jzoj4273-圣章-精灵使的魔法语【线段树】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
大意
有n個括號,有左有右,求一個區間內有多少個括號不能相互匹配。中間會改變某些括號的方向。
解題思路
線段樹維護兩個數lm(left?moreleftmore),rm(right?morerightmore)分別表示這個區間內多余的左括號和多余的右括號(是能相互匹配的,如“)()(”這兩個括號就不能相互匹配)。然后我們需要考慮兩段區間如何合并。
我們想一下,已經計算好的一個區間中的左括號是不能和右括號相互匹配的,但是在它右邊的區間中的所有多余的右括號都能和這個區間中的左括號相互匹配,所以我們可以得到:
相反,在這個區間的左邊的區間內所有的左邊括號都可以和這個區間內的右括號相互匹配:
t[x].rm=t[x?2].rm+max(0,t[x?2+1].rm?t[x?2].lm)t[x].rm=t[x?2].rm+max(0,t[x?2+1].rm?t[x?2].lm)
然后維護查詢修改都是正常操作
代碼
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define MN 150001 using namespace std; struct tnode{int rm,lm,l,r; }t[MN*4]; int n,m,x,y,anl,anr,zal,zar; char c[7],str[MN]; void build(int x,int l,int r){t[x].l=l;t[x].r=r;if (l==r) {t[x].lm=str[l]=='('?1:0;t[x].rm=str[l]==')'?1:0;return;}int mid=(l+r)>>1;build(x<<1,l,mid);build(x<<1|1,mid+1,r);t[x].lm=t[x*2+1].lm+max(0,t[x*2].lm-t[x*2+1].rm);t[x].rm=t[x*2].rm+max(0,t[x*2+1].rm-t[x*2].lm);//維護 } void updata(int x,int z) {if (t[x].l==z&&t[x].r==z){t[x].rm^=1,t[x].lm^=1;return;}int mid=(t[x].l+t[x].r)>>1;if (z<=mid) updata(x<<1,z);else updata(x<<1|1,z);t[x].lm=t[x*2+1].lm+max(0,t[x*2].lm-t[x*2+1].rm);t[x].rm=t[x*2].rm+max(0,t[x*2+1].rm-t[x*2].lm);//維護 } void find(int x,int l,int r) {if (t[x].l==l&&t[x].r==r){anl+=max(0,t[x].rm-anr);anr=t[x].lm+max(0,anr-t[x].rm);//累計return;}int mid=(t[x].l+t[x].r)>>1;if (r<=mid) find(x<<1,l,r);else if (l>mid) find(x<<1|1,l,r);else {find(x<<1,l,mid);find(x<<1|1,mid+1,r);} } int main() {//freopen("elf.in","r",stdin);//freopen("elf.out","w",stdout);scanf("%d%d",&n,&m);scanf("%s",str+1);build(1,1,n);for (int i=1;i<=m;i++){scanf("%s",c+1);if (c[1]=='Q'){scanf("%d%d",&x,&y);find(1,x,y);printf("%d %d\n",anl,anr);anl=0;anr=0;}else{scanf("%d",&x);updata(1,x);}} }總結
以上是默认站点為你收集整理的jzoj4273-圣章-精灵使的魔法语【线段树】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 也许迷途的惆怅敲碎我的脚步是什么歌曲 光
- 下一篇: jzoj4274-终章-剑之魂【位运算,