YbtOJ 「数据结构」第4章 线段树
不想 dp 了怎么办?开个新坑吧。
例题1.求区间和
树状数组不香吗,28行解决(bushi 所以懒得打线段树了。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,c[100005];
int lowbit(int x) {return x&(-x);}
void add(int x,int k){
for(int i=x;i<=n;i+=lowbit(i)) c[i]+=k;
}
int ask(int x)
{
int ans=0;
for(int i=x;i;i-=lowbit(i)) ans+=c[i];
return ans;
}
int sum(int l,int r){
return ask(r)-ask(l-1);
}
signed main()
{
scanf("%lld%lld",&n,&m);
for(int i=1,k,a,b;i<=m;i++)
{
scanf("%lld%lld%lld",&k,&a,&b);
if(k) cout<<sum(a,b)<<endl;
else add(a,b);
}
return 0;
}
例题2.区间查改
板子。这次老老实实写线段树。现在是 15:10,猜猜我码一遍板子要多久qwq
15:23 好了我码完了,这什么老年人手速啊。今日大聪明行为:N=1e6-5。
code
#include<bits/stdc++.h>
#define int long long
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int N=1e6+5;
int n,q,a[N],tr[N<<2],lz[N<<2];
void build(int now,int l,int r)
{
if(l==r) {tr[now]=a[l];return;}
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
tr[now]=tr[ls]+tr[rs];
}
void push_down(int now,int l,int r)
{
int mid=(l+r)>>1;
tr[ls]+=lz[now]*(mid-l+1);tr[rs]+=lz[now]*(r-mid);
lz[ls]+=lz[now];lz[rs]+=lz[now];
lz[now]=0;
}
void modify(int now,int l,int r,int ml,int mr,int k)
{
if(l==ml&&r==mr)
{
tr[now]+=k*(r-l+1);
lz[now]+=k;
return;
}
push_down(now,l,r);
int mid=(l+r)>>1;
if(mr<=mid) modify(ls,l,mid,ml,mr,k);
else if(ml>mid) modify(rs,mid+1,r,ml,mr,k);
else modify(ls,l,mid,ml,mid,k),modify(rs,mid+1,r,mid+1,mr,k);
tr[now]=tr[ls]+tr[rs];
}
int query(int now,int l,int r,int ml,int mr)
{
if(l==ml&&r==mr) return tr[now];
push_down(now,l,r);
int mid=(l+r)>>1;
if(mr<=mid) return query(ls,l,mid,ml,mr);
else if(ml>mid) return query(rs,mid+1,r,ml,mr);
else return query(ls,l,mid,ml,mid)+query(rs,mid+1,r,mid+1,mr);
}
signed main()
{
scanf("%lld%lld",&n,&q);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
for(int i=1,op,l,r,k;i<=q;i++)
{
scanf("%lld%lld%lld",&op,&l,&r);
if(op==1)
{
scanf("%lld",&k);
modify(1,1,n,l,r,k);
}
else cout<<query(1,1,n,l,r)<<endl;
}
return 0;
}
例题3.公园遛狗
线段树节点维护区间内最大子段和。
为合并两个区间,还需维护每个区间和,最大前缀和,最大后缀和。
code
#include<bits/stdc++.h>
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int N=5e5+5;
int n,q,a[N];
struct node{
int m,L,R,s;
}tr[N<<2];
void pushup(int now)
{
tr[now].s=tr[ls].s+tr[rs].s;
tr[now].m=max(tr[ls].m,tr[rs].m);
tr[now].m=max(tr[now].m,tr[ls].R+tr[rs].L);
tr[now].L=max(tr[ls].L,tr[ls].s+tr[rs].L);
tr[now].R=max(tr[rs].R,tr[rs].s+tr[ls].R);
}
void build(int now,int l,int r)
{
if(l==r)
{
tr[now].s=tr[now].L=tr[now].R=tr[now].m=a[l];
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
pushup(now);
}
void modify(int now,int l,int r,int x,int k)
{
if(l==r)
{
tr[now].s=tr[now].L=tr[now].R=tr[now].m=k;
return;
}
int mid=(l+r)>>1;
if(x<=mid) modify(ls,l,mid,x,k);
else modify(rs,mid+1,r,x,k);
pushup(now);
}
node query(int now,int l,int r,int ml,int mr)
{
if(l==ml&&r==mr) return tr[now];
int mid=(l+r)>>1;
if(mr<=mid) return query(ls,l,mid,ml,mr);
else if(ml>mid) return query(rs,mid+1,r,ml,mr);
else
{
node b=query(ls,l,mid,ml,mid),c=query(rs,mid+1,r,mid+1,mr);
node ans;
ans.s=b.s+c.s;
ans.L=max(b.L,b.s+c.L);ans.R=max(c.R,b.R+c.s);
ans.m=max(b.m,c.m);
ans.m=max(ans.m,b.R+c.L);
return ans;
}
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
for(int i=1,op,l,r;i<=q;i++)
{
scanf("%d%d%d",&op,&l,&r);
if(op==1)
{
if(l>r) swap(l,r);
node qwq=query(1,1,n,l,r);
cout<<qwq.m<<endl;
}
else modify(1,1,n,l,r);
}
return 0;
}
例题4.维护序列
维护两个懒标记。更新顺序先乘后加。(远古时代的代码
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
int tr[400001];
int n,a[100001],lz1[400001],lz2[400001],m,p1;
void build(int p,int l,int r){
lz1[p]=1;
if(l==r)
{
tr[p]=a[l];
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
tr[p]=tr[p*2]+tr[p*2+1];
}
void push_down(int p,int l,int r){
int mid=(l+r)/2;
if(lz1[p]!=1)
{
(lz1[p*2]*=lz1[p]%p1)%=p1;
(lz1[p*2+1]*=lz1[p]%p1)%=p1;
(lz2[p*2]*=lz1[p])%=p1;
(lz2[p*2+1]*=lz1[p])%=p1;
(tr[p*2]*=(lz1[p])%p1)%=p1;
(tr[p*2+1]*=(lz1[p])%p1)%=p1;
lz1[p]=1;
}
if(lz2[p]>0)
{
(lz2[p*2]+=lz2[p]%p1)%=p1;
(lz2[p*2+1]+=lz2[p]%p1)%=p1;
(tr[p*2]+=(lz2[p]*(mid-l+1))%p1)%=p1;
(tr[p*2+1]+=(lz2[p]*(r-(mid+1)+1))%p1)%=p1;
lz2[p]=0;
}
}
void modify1(int p,int l,int r,int ml,int mr,int x){
if(l==ml&&r==mr)
{
(tr[p]*=x%p1)%=p1;
(lz1[p]*=x%p1)%=p1;
(lz2[p]*=x%p1)%=p1;
return;
}
int mid=(l+r)/2;
push_down(p,l,r);
if(mr<=mid) modify1(p*2,l,mid,ml,mr,x);
else if(ml>=mid+1) modify1(p*2+1,mid+1,r,ml,mr,x);
else
{
modify1(p*2,l,mid,ml,mid,x);
modify1(p*2+1,mid+1,r,mid+1,mr,x);
}
tr[p]=(tr[p*2]+tr[p*2+1])%p1;
}
void modify2(int p,int l,int r,int ml,int mr,int x){
if(l==ml&&r==mr)
{
tr[p]+=(x*(r-l+1))%p1;
lz2[p]+=x;
return;
}
int mid=(l+r)/2;
push_down(p,l,r);
if(mr<=mid) modify2(p*2,l,mid,ml,mr,x);
else if(ml>=mid+1) modify2(p*2+1,mid+1,r,ml,mr,x);
else
{
modify2(p*2,l,mid,ml,mid,x);
modify2(p*2+1,mid+1,r,mid+1,mr,x);
}
tr[p]=(tr[p*2]+tr[p*2+1])%p1;
}
int query(int p,int l,int r,int ql,int qr){
if(l==ql&&qr==r) return tr[p];
int mid=(l+r)/2;
push_down(p,l,r);
if(qr<=mid) return query(p*2,l,mid,ql,qr);
if(ql>mid) return query(p*2+1,mid+1,r,ql,qr);
else return (query(p*2,l,mid,ql,mid)+query(p*2+1,mid+1,r,mid+1,qr))%p1;
}
signed main(){
cin>>n>>p1;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
cin>>m;
build(1,1,n);
for(int i=1,u,x,ql,qr;i<=m;i++)
{
cin>>u;
if(u==1) cin>>ql>>qr>>x,modify1(1,1,n,ql,qr,x);
else if(u==2) cin>>ql>>qr>>x,modify2(1,1,n,ql,qr,x);
else cin>>ql>>qr,cout<<(query(1,1,n,ql,qr))%p1<<endl;
}
return 0;
}
例题5.字符串排序
观察到只有 26 种字符。类似桶排,分别统计每个字符数量,排序时区间覆盖。
code
#include<bits/stdc++.h>
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int N=1e5+5;
int n,m;
char s[N];
int lz[N<<2];
struct node{
int w[30];
node(){memset(w,0,sizeof(w));}
}tr[N<<2];
void build(int now,int l,int r)
{
lz[now]=-1;
if(l==r)
{
tr[now].w[s[l]-'a']=1;
//cout<<now<<" "<<s[l]-'a'<<endl;
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
for(int i=0;i<26;i++) tr[now].w[i]=tr[ls].w[i]+tr[rs].w[i];
//cout<<now<<" "<<l<<" "<<r<<" "<<tr[now].w[1]<<endl;
}
void push_down(int now,int l,int r)
{
if(lz[now]==-1) return;
int k=lz[now],mid=(l+r)>>1;
for(int i=0;i<26;i++) tr[ls].w[i]=tr[rs].w[i]=0;
tr[ls].w[k]=mid-l+1;tr[rs].w[k]=r-mid;
lz[ls]=k,lz[rs]=k;
lz[now]=-1;
}
void modify(int now,int l,int r,int ml,int mr,int k)
{
if(l==ml&&r==mr)
{
for(int i=0;i<26;i++) tr[now].w[i]=0;
tr[now].w[k]=(r-l+1);lz[now]=k;
return;
}
push_down(now,l,r);
int mid=(l+r)>>1;
if(mr<=mid) modify(ls,l,mid,ml,mr,k);
else if(ml>mid) modify(rs,mid+1,r,ml,mr,k);
else modify(ls,l,mid,ml,mid,k),modify(rs,mid+1,r,mid+1,mr,k);
for(int i=0;i<26;i++) tr[now].w[i]=tr[ls].w[i]+tr[rs].w[i];
}
node query(int now,int l,int r,int ml,int mr)
{
//cout<<now<<" "<<l<<" "<<r<<endl;
if(l==ml&&r==mr)
{
//for(int i=1;i<=
return tr[now];
}
int mid=(l+r)>>1;
push_down(now,l,r);
if(mr<=mid) return query(ls,l,mid,ml,mr);
else if(ml>mid) return query(rs,mid+1,r,ml,mr);
else
{
node c=query(ls,l,mid,ml,mid),d=query(rs,mid+1,r,mid+1,mr);
node ans;
for(int i=0;i<26;i++) ans.w[i]=c.w[i]+d.w[i];
return ans;
}
}
void s0rt(int op,int l,int r)
{
node qwq=query(1,1,n,l,r);
if(op)
{
int now=l;
for(int i=0;i<26;i++)
{
if(!qwq.w[i]) continue;
//cout<<i<<endl;
modify(1,1,n,now,now+qwq.w[i]-1,i);
now+=qwq.w[i];
}
}
else
{
int now=l;
for(int i=25;i>=0;i--)
{
if(!qwq.w[i]) continue;
modify(1,1,n,now,now+qwq.w[i]-1,i);
now+=qwq.w[i];
}
}
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",s+1);
build(1,1,n);
//for(int i=0;i<4;i++) cout<<tr[2].w[i]<<endl;
for(int i=1,op,l,r;i<=m;i++)
{
scanf("%d%d%d",&l,&r,&op);
s0rt(op,l,r);
}
for(int i=1;i<=n;i++)
{
node qwq=query(1,1,n,i,i);
for(int j=0;j<26;j++) if(qwq.w[j]) putchar(j+'a');
}
//node qwq=query(1,1,n,1,3);
//for(int i=0;i<4;i++) cout<<qwq.w[i]<<endl;
return 0;
}
/*
5 2
cabcd
1 3 1
3 5 0
*/
1.取模问题
维护区间和和区间最大值。最大值小于模数就直接 return 掉。
其余暴力取模。每次取模数值至少减半,故取模次数不会太多。
code
#include<bits/stdc++.h>
#define int long long
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int N=1e5+5;
int n,m,a[N];
int maxn[N<<2],tr[N<<2];
void pushup(int now)
{
maxn[now]=max(maxn[ls],maxn[rs]);
tr[now]=tr[ls]+tr[rs];
}
void build(int now,int l,int r)
{
if(l==r)
{
maxn[now]=tr[now]=a[l];
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
pushup(now);
}
void modify(int now,int l,int r,int x,int k)
{
if(l==r)
{
maxn[now]=tr[now]=k;
return;
}
int mid=(l+r)>>1;
if(x<=mid) modify(ls,l,mid,x,k);
else modify(rs,mid+1,r,x,k);
pushup(now);
}
int query(int now,int l,int r,int ml,int mr)
{
if(l==ml&&r==mr) return tr[now];
int mid=(l+r)>>1;
if(mr<=mid) return query(ls,l,mid,ml,mr);
else if(ml>mid) return query(rs,mid+1,r,ml,mr);
else return query(ls,l,mid,ml,mid)+query(rs,mid+1,r,mid+1,mr);
}
void mod(int now,int l,int r,int ml,int mr,int x)
{
int mid=(l+r)>>1;
if(l==ml&&r==mr)
{
if(maxn[now]<x) return;
if(l==r)
{
tr[now]%=x;maxn[now]%=x;
return;
}
mod(ls,l,mid,ml,mid,x);mod(rs,mid+1,r,mid+1,mr,x);
pushup(now);
return;
}
if(mr<=mid) mod(ls,l,mid,ml,mr,x);
else if(ml>mid) mod(rs,mid+1,r,ml,mr,x);
else mod(ls,l,mid,ml,mid,x),mod(rs,mid+1,r,mid+1,mr,x);
pushup(now);
}
signed main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
for(int i=1,op,l,r,x;i<=m;i++)
{
scanf("%lld%lld%lld",&op,&l,&r);
if(op==1) cout<<query(1,1,n,l,r)<<endl;
else if(op==2) scanf("%lld",&x),mod(1,1,n,l,r,x);
else modify(1,1,n,l,r);
}
return 0;
}
2.魔法传输
差分,则修改操作转换为区间加,单点查询转化为求前缀和。
然后就变成裸的板子了。
code
#include<bits/stdc++.h>
#define int long long
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int N=1e5+5;
const int mod=1e9+7;
int n,q,a[N],tr[N<<2],lz[N<<2];
void push_down(int now,int l,int r)
{
int mid=(l+r)>>1;
tr[ls]=(tr[ls]+lz[now]*(mid-l+1))%mod;tr[rs]=(tr[rs]+lz[now]*(r-mid))%mod;
lz[ls]=(lz[ls]+lz[now])%mod;lz[rs]=(lz[rs]+lz[now])%mod;
lz[now]=0;
}
void modify(int now,int l,int r,int ml,int mr,int k)
{
if(ml>mr||mr>n||ml<1) return;
if(l==ml&&r==mr)
{
tr[now]=(tr[now]+k*(r-l+1))%mod;
lz[now]=(lz[now]+k)%mod;
return;
}
push_down(now,l,r);
int mid=(l+r)>>1;
if(mr<=mid) modify(ls,l,mid,ml,mr,k);
else if(ml>mid) modify(rs,mid+1,r,ml,mr,k);
else modify(ls,l,mid,ml,mid,k),modify(rs,mid+1,r,mid+1,mr,k);
tr[now]=(tr[ls]+tr[rs])%mod;
}
int query(int now,int l,int r,int ml,int mr)
{
if(l==ml&&r==mr) return tr[now];
push_down(now,l,r);
int mid=(l+r)>>1;
if(mr<=mid) return query(ls,l,mid,ml,mr);
else if(ml>mid) return query(rs,mid+1,r,ml,mr);
else return (query(ls,l,mid,ml,mid)+query(rs,mid+1,r,mid+1,mr))%mod;
}
signed main()
{
scanf("%lld%lld",&n,&q);
for(int i=1;i<=q;i++)
{
char c;c=getchar();
while(c!='C'&&c!='Q') c=getchar();
if(c=='C')
{
int l,r;
scanf("%lld%lld",&l,&r);
modify(1,1,n,l,r,1);
modify(1,1,n,r+1,r+1,-(r-l+1));
}
else
{
int x;
scanf("%lld",&x);
cout<<query(1,1,n,1,x)%mod<<endl;
}
}
return 0;
}
3.队伍整理
喜提全网首A/cy
不用离散化不用链表不用权值线段树(那篇题解实在离谱)。其实这题不难,不要被网上题解劝退了qwq
把题分成两部分来看。
询问前面成绩最好的同学:这就是问前面人排名的最小值。那把没有人的位置都单点赋值成 \(inf\),然后线段树维护区间最小值即可。
最少移动多少个人:开一个数组记录每个位置是否有人。枚举每个长度为 \(n\) 的区间,通过前面那个数组的区间和判断这个区间有几个空位。移动时,我们把不在该区间的人都移进来。所以,空位最少的区间的空位数就是答案。这个东西在最后 O(n) 扫一下就好了。
实现细节:开一个 map 来记录每个排名的人所在的位置,省去了离散化的麻烦。总体写起来码量不大,80 行左右。
坑点:注意查询结果是 inf 时也要判作无解。
不知道讲清楚了没有/wq
upd:抱歉之前做麻烦了,不需要树状数组,已经更新了题解和代码。h2s 是神!
code
#include<bits/stdc++.h>
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int inf=2e9;
const int N=2e5+5;
int n,m,a[N];
map<int,int> w;
int tr[N<<2],cnt;
//线段树
void build(int now,int l,int r)
{
if(l==r)
{
tr[now]=a[l];
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
tr[now]=min(tr[ls],tr[rs]);
}
void modify(int now,int l,int r,int x,int k)
{
if(l==r)
{
tr[now]=k;
return;
}
int mid=(l+r)>>1;
if(x<=mid) modify(ls,l,mid,x,k);
else modify(rs,mid+1,r,x,k);
tr[now]=min(tr[ls],tr[rs]);
}
int query(int now,int l,int r,int ml,int mr)
{
if(mr<ml) return -1;
if(l==ml&&r==mr) return tr[now];
int mid=(l+r)>>1;
if(mr<=mid) return query(ls,l,mid,ml,mr);
else if(ml>mid) return query(rs,mid+1,r,ml,mr);
else return min(query(ls,l,mid,ml,mid),query(rs,mid+1,r,mid+1,mr));
}
int ct[N];
int main()
{
scanf("%d%d",&n,&m);cnt=n;
for(int i=1;i<=n+m;i++) a[i]=inf;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),w[a[i]]=i,ct[i]=1;
//for(int i=1;i<=n;i++) cout<<sum(i,i)<<" ";
build(1,1,n+m);
for(int i=1;i<=m;i++)
{
char c;int x;
c=getchar();
while(c!='A'&&c!='M') c=getchar();
scanf("%d",&x);
if(c=='A')
{
if(!w[x]) cout<<"-1"<<endl;
else if(query(1,1,n+m,1,w[x]-1)==inf) cout<<"-1"<<endl;
else cout<<query(1,1,n+m,1,w[x]-1)<<endl;
}
else
{
modify(1,1,n+m,w[x],inf);
modify(1,1,n+m,++cnt,x);
ct[(int)w[x]]=0;ct[cnt]=1;w[x]=cnt;
}
}
int maxn=0,sum=0;
for(int i=1;i<n;i++) sum+=ct[i];
for(int i=1;i<=cnt-n+1;i++)
{
sum-=ct[i-1];sum+=ct[i+n-1];
maxn=max(maxn,sum);
}
cout<<n-maxn<<endl;
return 0;
}
4.和或异或
线段树维护答案,pushup 时根据深度判断一下是或还是异或。
code
#include<bits/stdc++.h>
#define int long long
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int N=1.4e5+5;
int n,q,qwq;
int tr[N<<2],a[N];
void pushup(int now,int dep)
{
if((qwq&1)^(dep&1))
{
tr[now]=tr[ls]^tr[rs];
//cout<<now<<" "<<tr[now]<<" "<<tr[ls]<<" "<<tr[rs]<<" 1"<<endl;
}
else
{
tr[now]=tr[ls]|tr[rs];
//cout<<now<<" "<<tr[now]<<" "<<tr[ls]<<" "<<tr[rs]<<" 2"<<endl;
}
}
void build(int now,int l,int r,int dep)
{
//cout<<now<<" "<<l<<" "<<r<<endl;
if(l==r) {tr[now]=a[l];return;}
int mid=(l+r)>>1;
build(ls,l,mid,dep+1);build(rs,mid+1,r,dep+1);
pushup(now,dep);
}
void modify(int now,int l,int r,int x,int k,int dep)
{
if(l==r) {tr[now]=k;return;}
int mid=(l+r)>>1;
if(x<=mid) modify(ls,l,mid,x,k,dep+1);
else modify(rs,mid+1,r,x,k,dep+1);
pushup(now,dep);
}
signed main()
{
scanf("%lld%lld",&n,&q);
qwq=n;n=pow(2,n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n,1);
for(int i=1,x,y;i<=q;i++)
{
scanf("%lld%lld",&x,&y);
modify(1,1,n,x,y,1);
cout<<tr[1]<<endl;
}
return 0;
}
5.括号匹配
维护区间内已匹配括号的数量、多余左括号的数量、多余右括号的数量。
为什么线段树这章的题都这么板啊qaq
code
#include<bits/stdc++.h>
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int N=4e5+5;
int n,m;
char s[N];
struct node{
int L,R,w;
}tr[N<<2];
void pushup(int now)
{
int qwq=min(tr[ls].L,tr[rs].R);
tr[now].w=tr[ls].w+tr[rs].w+2*qwq;
tr[now].L=tr[ls].L+tr[rs].L-qwq;
tr[now].R=tr[ls].R+tr[rs].R-qwq;
}
void build(int now,int l,int r)
{
if(l==r)
{
if(s[l]=='(') tr[now].L=1;
else tr[now].R=1;
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
pushup(now);
}
node query(int now,int l,int r,int ml,int mr)
{
if(l==ml&&r==mr) return tr[now];
int mid=(l+r)>>1;
if(mr<=mid) return query(ls,l,mid,ml,mr);
else if(ml>mid) return query(rs,mid+1,r,ml,mr);
else
{
node ll=query(ls,l,mid,ml,mid),rr=query(rs,mid+1,r,mid+1,mr);
int qwq=min(ll.L,rr.R);
node ans;
ans.w=ll.w+rr.w+2*qwq;
ans.L=ll.L+rr.L-qwq;
ans.R=ll.R+rr.R-qwq;
return ans;
}
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",s+1);
build(1,1,n);
for(int i=1,l,r;i<=m;i++)
{
scanf("%d%d",&l,&r);
node qaq=query(1,1,n,l,r);
cout<<qaq.w<<endl;
}
return 0;
}
本文来自博客园,作者:樱雪喵,转载请注明原文链接:https://www.cnblogs.com/ying-xue/p/16591645.html