7-14 Yet Another Bracket Sequence
给定一个序列,m次改变序列,问序列是否括号匹配。
把(看做+1,)看做-1,那么括号匹配的条件即为1到n的区间最小前缀和为0,且pre[ n ] 为0,用线段树模拟即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N = 1e5+500; int pre[N]; struct node{ int s,l,r,lz; }tree[N<<2]; void push_up(int x){ tree[x].s=min(tree[x<<1].s,tree[x<<1|1].s); } void push_down(int x){ if(!tree[x].lz)return ; tree[x<<1].s+=tree[x].lz,tree[x<<1|1].s+=tree[x].lz; tree[x<<1].lz+=tree[x].lz,tree[x<<1|1].lz+=tree[x].lz; tree[x].lz=0; } void build(int x,int l,int r){ tree[x].l=l;tree[x].r=r; if(l==r){ tree[x].s=pre[l]; return ; } int mid=(l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); push_up(x); } void modify(int x,int l,int r,int val){ if(tree[x].l>=l&&tree[x].r<=r){ tree[x].lz+=val; tree[x].s+=val; return ; } push_down(x); int mid=(tree[x].l+tree[x].r)>>1; if(l<=mid)modify(x<<1,l,r,val); if(r>mid)modify(x<<1|1,l,r,val); push_up(x); } char s[N]; int main(){ int n,m; scanf("%d %d %s",&n,&m,s+1); pre[0]=0; for(int i=1;i<=n;i++){ if(s[i]=='(')pre[i]=pre[i-1]+1; else pre[i]=pre[i-1]-1; } // for(int i=1;i<=n;i++)pre[i]=pre[i-1]+(s[i]=='(')?1:-1; int sum=pre[n]; build(1,1,n); while(m--){ int x;scanf("%d",&x); if(s[x]=='(')s[x]=')',sum-=2,modify(1,x,n,-2); else s[x]='(',sum+=2,modify(1,x,n,2); // cout<<"test : "<<tree[1].s<<" "<<sum<<endl; if(tree[1].s==0&&sum==0)puts("Yes"); else puts("No"); } // system("pause"); return 0; }
Can you answer these queries III
单点修改和询问区间最大子串和,设置 lmax 和 rmax,合并即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N=5e5+500; typedef long long ll; const int inf=1e9; struct node{ int l,r; int sum,val,lmax,rmax; node(){ val=lmax=rmax=-inf; l=r=sum=0; } }tree[N<<2]; int a[N]; void push_up(int x){ tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum; tree[x].lmax=max(tree[x<<1].lmax,tree[x<<1].sum+tree[x<<1|1].lmax); tree[x].rmax=max(tree[x<<1|1].rmax,tree[x<<1|1].sum+tree[x<<1].rmax); tree[x].val=max(max(tree[x<<1].val,tree[x<<1|1].val),tree[x<<1].rmax+tree[x<<1|1].lmax); } void build(int x,int l,int r){ // cout<<x<<endl; tree[x].l=l;tree[x].r=r; if(l==r){ tree[x].sum=tree[x].lmax=tree[x].rmax=tree[x].val=a[l]; return ; } int mid=(l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); push_up(x); } void modify(int x,int rt){ if(tree[rt].l==tree[rt].r){ tree[rt].sum=tree[rt].lmax=tree[rt].rmax=tree[rt].val=a[x]; return ; } int mid=(tree[rt].l+tree[rt].r)>>1; if(x<=mid)modify(x,rt<<1); else modify(x,rt<<1|1); push_up(rt); } node query(int a,int b,int rt){ if(tree[rt].l>=a&&tree[rt].r<=b){ return tree[rt]; } int mid=(tree[rt].l+tree[rt].r)>>1; node lnode,rnode,ret; if(a<=mid){ lnode=query(a,b,rt<<1); } if(b>mid){ rnode=query(a,b,rt<<1|1); } ret.sum=lnode.sum+rnode.sum; ret.lmax=max(lnode.lmax,lnode.sum+rnode.lmax); ret.rmax=max(rnode.rmax,rnode.sum+lnode.rmax); ret.val=max(max(lnode.val,rnode.val),lnode.rmax+rnode.lmax); return ret; } int main(){ int n,m;cin>>n>>m; for(int i=1;i<=n;i++)scanf("%d",&a[i]); build(1,1,n); while(m--){ int k,x,y; scanf("%d %d %d",&k,&x,&y); if(k==1){ if(x>y)swap(x,y); printf("%d ",query(x,y,1).val); } else { a[x]=y; modify(x,1); } } // system("pause"); return 0; }
Can you answer these queries III
实现区间加,询问区间gcd。
有区间加的形式,无法直接维护区间gcd。
考虑辗转相除法,gcd($x$,$y$,$z$)=gcd($x$,$y-x$,$z-y$)
对于区间加:让差分数组$b_l$+$d$,$b_{r+1}$-$d$
对于区间gcd,gcd[l,r]=gcd($a_l$,gcd[ b [l+1,r] ] )
用一个线段树维护差分数组,支持区间gcd和单点修改
考虑数组a动态变化,需要支持区间加和单点查询,用一个树状数组模拟,
在维护差分数组的区间gcd会出现负数的情况,取绝对值即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define int long long const int N=6e5+500; int gcd(int a,int b){return b==0?a:gcd(b,a%b);} int a[N],b[N]; struct node{ int g,l,r; }tree[N<<4]; void push_up(int x){ tree[x].g=gcd(tree[x<<1].g,tree[x<<1|1].g); } void build(int x,int l,int r){ tree[x].l=l;tree[x].r=r; if(l==r){ tree[x].g=b[l]; return ; } int mid=(l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); push_up(x); } void modify(int rt,int x,int d){ if(tree[rt].l==x&&tree[rt].r==x){ tree[rt].g+=d; return ; } int mid=(tree[rt].l+tree[rt].r)>>1; if(x<=mid)modify(rt<<1,x,d); else if(x>mid)modify(rt<<1|1,x,d); push_up(rt); } int query(int x,int l,int r){ if(tree[x].l>=l&&tree[x].r<=r){ return tree[x].g; } int mid=(tree[x].l+tree[x].r)>>1; if(r<=mid)return query(x<<1,l,r); if(l>mid)return query(x<<1|1,l,r); return abs( gcd(query(x<<1,l,r),query(x<<1|1,l,r)) ); } int T[N]; #define lowbit(x)(x&-x) int n,m; void add(int x,int d){ for(;x<=n;x+=lowbit(x))T[x]+=d; } int Sum(int x){ int sum=0; for(;x;x-=lowbit(x))sum+=T[x]; return sum; } signed main(){ scanf("%lld %ld",&n,&m); // cin>>n>>m; for(int i=1;i<=n;i++)scanf("%lld",&a[i]); b[1]=a[1]; add(1,b[1]); for(int i=2;i<=n;i++)b[i]=a[i]-a[i-1],add(i,b[i]); build(1,1,n); while(m--){ char op;int x,y,z; getchar(); scanf("%c",&op); // cout<<"test :"<<op<<endl; if(op=='C'){ scanf("%lld %lld %lld",&x,&y,&z); modify(1,x,z);add(x,z); if(y+1<=n)modify(1,y+1,-z),add(y+1,-z); } else { scanf("%lld %lld",&x,&y); // cout<<"ans :"; if(x==y)printf("%lld ",Sum(x)); else printf("%lld ",gcd( Sum(x),query(1,x+1,y) ) ); } } // system("pause"); return 0; }
楼兰图腾
树状数组维护逆序对即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N=8e5+500; #define lowbit(x)(x&-x) typedef long long ll; ll tree[N],y[N],l[N],r[N]; int n; void init(){ memset(tree,0,sizeof tree); // memset(l,0,sizeof l); // memset(r,0,sizeof r); } void add(int x,ll d){ for(;x<=n;x+=lowbit(x))tree[x]+=d; } ll ask(int x){ ll sum=0; for(;x;x-=lowbit(x))sum+=tree[x]; return sum; } int main(){ cin>>n; for(int i=1;i<=n;i++)scanf("%d",&y[i]); ll ans1=0,ans2=0; init(); for(int i=1;i<=n;i++){ l[i]=max(0ll,(i-1)-ask(y[i])); add(y[i],1); } init(); for(int i=n;i>=1;i--){ r[i]=max(0ll,(n-i)-ask(y[i])); add(y[i],1); } for(int i=1;i<=n;i++)ans1+=l[i]*r[i]; init(); for(int i=1;i<=n;i++){ l[i]=ask(y[i]-1); add(y[i],1); } init(); for(int i=n;i>=1;i--){ r[i]=ask(y[i]-1); add(y[i],1); } for(int i=1;i<=n;i++)ans2+=l[i]*r[i]; cout<<ans1<<" "<<ans2<<endl; // system("pause"); return 0; }