这道题的意思是给你一组开关,开始时全部是关的。
m组询问,每次询问要么把某个区间的开关置换,关变成开,开变成关
要么求出某个区间开关为开的数量。
明显是道线段树的题目。
不需要建树,需要更新,需要查询,需要push,懒标记一个。
我们需要维护一个懒标记,就是操作的奇偶次数,奇数相当于执行一次,偶数相当于没有执行
还要维护该区间打开的开关的个数。每次置换节点值修改为区间长度-开关个数
然后修改后自底向顶更新每个相关节点
#include<bits/stdc++.h>
using namespace std;
struct node{
int v;
int mark;
}tree[300010];
void push(int pos,int cnt1,int cnt2){
tree[pos<<1].mark^=tree[pos].mark;
if(tree[pos].mark==1) tree[pos<<1].v=cnt1-tree[pos<<1].v;
tree[pos<<1|1].mark^=tree[pos].mark;
if(tree[pos].mark==1)tree[pos<<1|1].v=cnt2-tree[pos<<1|1].v;
tree[pos].mark=0;
}
void update(int pos,int l,int r,int x,int y){
if(x<=l&&r<=y){
tree[pos].v=r-l+1-tree[pos].v;
tree[pos].mark^=1;
return;
}
int mid=(l+r)/2;
push(pos,mid-l+1,r-mid);
if((l<x&&mid>=x)||l>=x) update(pos<<1,l,mid,x,y);
if((r>y&&mid+1<=y)||r<=y) update(pos<<1|1,mid+1,r,x,y);
tree[pos].v=tree[pos<<1].v+tree[pos<<1|1].v;
}
int query(int pos,int l,int r,int x,int y){
if(x<=l&&r<=y){
return tree[pos].v;
}
int mid=(l+r)/2;
push(pos,mid-l+1,r-mid);
int res=0;
if((l<x&&mid>=x)||l>=x) res+=query(pos<<1,l,mid,x,y);
if((r>y&&mid+1<=y)||r<=y)res+=query(pos<<1|1,mid+1,r,x,y);
return res;
}
int main(){
int n,m;
cin>>n>>m;
while(m--){
int od,l,r;
cin>>od>>l>>r;
if(od==0){
update(1,1,n,l,r);
}
else {
cout<<query(1,1,n,l,r)<<endl;
}
}
return 0;
}
这道题需要建树,需要更新,需要查询,需要push。懒标记两个
一个是首项,一个是公差。
其中首项是会发生变化的,
首先的值要加上x到l的偏移量才能算这个区间的首项
所有push的时候对于右儿子区间的首先等于左儿子的长度*d+左儿子的首项
其他操作就更模板题差不多了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct node{
ll k,d;
ll v;
}tree[300010];
int a[100010];
void build(int pos,int l,int r){
if(l>r)return;
if(l==r){
tree[pos].v=a[l];
return;
}
int mid=(l+r)/2;
build(pos<<1,l,mid);
build(pos<<1|1,mid+1,r);
tree[pos].v=tree[pos<<1].v+tree[pos<<1|1].v;
}
void push(int pos,int len1,int len2){
ll k=tree[pos].k,d=tree[pos].d;
ll k2=k+len1*d;
tree[pos<<1].k+=k;
tree[pos<<1].d+=d;
tree[pos<<1].v+=len1*k+len1*(len1-1)/2*d;
tree[pos<<1|1].k+=k2;
tree[pos<<1|1].d+=d;
tree[pos<<1|1].v+=len2*k2+len2*(len2-1)/2*d;
tree[pos].k=tree[pos].d=0;
}
void update(int pos,int l,int r,int x,int y,int k,int d){
if(x<=l&&r<=y){
int len=r-l+1;
int k1=k+(l-x)*d;
tree[pos].v+=len*k1+len*(len-1)/2*d;
tree[pos].k+=k1;
tree[pos].d+=d;
return;
}
int mid=(l+r)/2;
push(pos,mid-l+1,r-mid);
if((l<x&&mid>=x)||l>=x)update(pos<<1,l,mid,x,y,k,d);
if((r>y&&mid+1<=y)||r<=y) update(pos<<1|1,mid+1,r,x,y,k,d);
tree[pos].v=tree[pos<<1].v+tree[pos<<1|1].v;
}
ll query(int pos,int l,int r,int k){
if(l==r){
return tree[pos].v;
}
int mid=(l+r)/2;
push(pos,mid-l+1,r-mid);
if(k<=mid){
return query(pos<<1,l,mid,k);
}
return query(pos<<1|1,mid+1,r,k);
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,1,n);
while(m--){
int od;
cin>>od;
if(od==1){
int l,r,k,d;
cin>>l>>r>>k>>d;
update(1,1,n,l,r,k,d);
}
else {
int p;
cin>>p;
cout<<query(1,1,n,p)<<endl;
}
}
return 0;
}
这道题更简单,不需要更新,直接建树和查询即可,懒标记也不需要了
#include<bits/stdc++.h>
using namespace std;
struct node{
int v;
}tree[300010];
int a[100010];
void build(int pos,int l,int r){
if(l==r){
tree[pos].v=a[l];
return;
}
int mid=(l+r)/2;
build(pos<<1,l,mid);
build(pos<<1|1,mid+1,r);
tree[pos].v=min(tree[pos<<1].v,tree[pos<<1|1].v);
}
int query(int pos,int l,int r,int x,int y){
if(x<=l&&r<=y){
return tree[pos].v;
}
int mid=(l+r)/2;
int res=1e9;
if((l<x&&mid>=x)||l>=x)res=min(res,query(pos<<1,l,mid,x,y));
if((r>y&&mid+1<=y)||r<=y)res=min(res,query(pos<<1|1,mid+1,r,x,y));
return res;
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
build(1,1,n);
while(m--){
int l,r;
cin>>l>>r;
cout<<query(1,1,n,l,r)<<' ';
}
return 0;
}
这道题目是到数学题加区间和的题目
我们要配成区间和的形式
不难发现我们要求出数的区间和 数平方的区间和
我们要设置一个懒标记,还要两个节点值,一个是数的区间和,一个是数平方的区间和
数区间和更新跟模板一样
数平方的区间更新则是加上
注意数平方的区间更新要先!!
然后接下来套模板就可以了
#include<bits/stdc++.h>
using namespace std;
struct node{
double v1,v2;
double mark;
}tree[300010];
double a[100010];
void build(int pos,int l,int r){
if(l==r){
tree[pos].v1=a[l];
tree[pos].v2=a[l]*a[l];
return;
}
int mid=(l+r)/2;
build(pos<<1,l,mid);
build(pos<<1|1,mid+1,r);
tree[pos].v1=tree[pos<<1].v1+tree[pos<<1|1].v1;
tree[pos].v2=tree[pos<<1].v2+tree[pos<<1|1].v2;
}
double push(int pos,int len1,int len2){
double mark=tree[pos].mark;
tree[pos<<1].mark+=mark;
tree[pos<<1].v2+=mark*mark*len1+2*mark*tree[pos<<1].v1;
tree[pos<<1].v1+=len1*mark;
tree[pos<<1|1].mark+=mark;
tree[pos<<1|1].v2+=mark*mark*len2+2*mark*tree[pos<<1|1].v1;
tree[pos<<1|1].v1+=len2*mark;
tree[pos].mark=0;
}
double query(int pos,int l,int r,int x,int y,int ty){
if(x<=l&&r<=y){
if(ty==1) return tree[pos].v1;
return tree[pos].v2;
}
int mid=(l+r)/2;
push(pos,mid-l+1,r-mid);
double res=0;
if((l<x&&mid>=x)||l>=x)res+=query(pos<<1,l,mid,x,y,ty);
if((r>y&&mid+1<=y)||r<=y)res+=query(pos<<1|1,mid+1,r,x,y,ty);
return res;
}
void update(int pos,int l,int r,int x,int y,double k){
if(x<=l&&r<=y){
int len=r-l+1;
tree[pos].v2+=len*k*k+2*k*tree[pos].v1;
tree[pos].v1+=k*len;
tree[pos].mark+=k;
return;
}
int mid=(l+r)/2;
push(pos,mid-l+1,r-mid);
if((l<x&&mid>=x)||l>=x)update(pos<<1,l,mid,x,y,k);
if((r>y&&mid+1<=y)||r<=y)update(pos<<1|1,mid+1,r,x,y,k);
tree[pos].v1=tree[pos<<1].v1+tree[pos<<1|1].v1;
tree[pos].v2=tree[pos<<1].v2+tree[pos<<1|1].v2;
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
build(1,1,n);
while(m--){
int od;
cin>>od;
double x,y,k;
if(od==1){
cin>>x>>y>>k;
update(1,1,n,x,y,k);
}
else if(od==2){
cin>>x>>y;
int len=y-x+1;
double avg=query(1,1,n,x,y,1)/len;
printf("%.4lf\n",avg);
}
else {
cin>>x>>y;
int len=y-x+1;
double avg=query(1,1,n,x,y,1)/len;
double tol=query(1,1,n,x,y,2)-2*query(1,1,n,x,y,1)*avg+len*avg*avg;
printf("%.4lf\n",tol/len);
}
}
return 0;
}
这道题跟前面四道题不同,可以直接用两个树状数组解决
对于每个位置的数,我们只要求出,比它的小的长度为2的上升序列个数
然后所有位置上的个数叠加即可
然后看代码更清楚
#include<bits/stdc++.h>
using namespace std;
#define maxm 100000
#define ll long long
int b1[100010];
int b2[100010];
void up(int k,int ty,int s){
for(int i=k;i<=maxm;i+=i&(-i)){
if(ty==1)b1[i]+=s;
else b2[i]+=s;
}
}
int qu(int k,int ty){
int res=0;
while(k){
if(ty==1)res+=b1[k];
else res+=b2[k];
k-=k&(-k);
}
return res;
}
int main(){
int n;
cin>>n;
ll res=0;
for(int i=1;i<=n;i++){
int x;
cin>>x;
res+=qu(x-1,2);
up(x,1,1);
int cnt=qu(x-1,1);
up(x,2,cnt);
}
cout<<res<<endl;
return 0;
}