/*单点更新,区间求和*/
/*应用:1.建空树,可以查询比某值大的数之和,然后单点更新*/
#define N 50050
int num[N];
struct Tree{
int l;
int r;
int sum;
}tree[4*N];
void build(int t,int l,int r){
tree[t].l=l;
tree[t].r=r;
if(tree[t].l==tree[t].r){
tree[t].sum=num[l];
return;
}
int mid=(l+r)/2;
build(2*t,l,mid);
build(2*t+1,mid+1,r);
tree[t].sum=tree[2*t].sum+tree[2*t+1].sum;
}
void update(int t,int pos,int val){
if(tree[t].l==tree[t].r){
tree[t].sum=val;
return;
}
int mid=(tree[t].l+tree[t].r)/2;
if(pos<=mid) /*这点注意,我们都把mid放到左边了*/
update(2*t,pos,val);
else
update(2*t+1,pos,val);
tree[t].sum=tree[2*t].sum+tree[2*t+1].sum;
}
int query(int t,int l,int r){
if(l<=tree[t].l&&r>=tree[t].r)
return tree[t].sum;
int mid=(tree[t].l+tree[t].r)/2,ans=0;
if(l<=mid) ans+=query(2*t,l,r);/*加完左边加上右边的,不用分情况考虑*/
if(r>mid) ans+=query(2*t+1,l,r);
return ans;
}
区间更新,区间求和(延迟标记)
#define ll long long
const int maxn = 111111;
ll num[maxn<<2];
struct Tree{
int l,r;
ll sum;
}tree[maxn<<2];
ll lazy[maxn<<2];
void down(int t, int len){
if(lazy[t]){
lazy[t<<1] += lazy[t];
lazy[t<<1|1] += lazy[t];/*延迟标记往下传*/
tree[t<<1].sum += lazy[t] * (len-(len>>1));/*左子树比右子树多1*/
tree[t<<1|1].sum += lazy[t] * (len>>1);
lazy[t] = 0; /*往下传完就赋0*/
}
}
void build(int l,int r,int t){
tree[t].l=l; tree[t].r=r;
lazy[t]=0;
if(l==r){
tree[t].sum=num[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,t<<1);
build(mid+1,r,t<<1|1);
tree[t].sum=tree[2*t].sum+tree[2*t+1].sum;
}
void update(int x,int l,int r,int t){
if(l<=tree[t].l&&r>=tree[t].r){
lazy[t]+=x;
tree[t].sum+=(ll)x*(tree[t].r-tree[t].l+1);
return;
}
down(t,tree[t].r-tree[t].l+1);
int mid=(tree[t].l+tree[t].r)>>1;
if(l<=mid) update(x,l,r,t<<1);
if(r>mid) update(x,l,r,t<<1|1);
tree[t].sum=tree[2*t].sum+tree[2*t+1].sum;
}
ll query(int l,int r,int t){
if(l<=tree[t].l&&r>=tree[t].r) return tree[t].sum;
down(t,tree[t].r-tree[t].l+1);
int mid=(tree[t].l+tree[t].r)>>1; ll ans=0;
if(l<=mid) ans+=query(l,r,2*t);/*加完左边加上右边的,不用分情况考虑*/
if(r>mid) ans+=query(l,r,2*t+1);
return ans;
}
区间更新,查种类数(位运算)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define ll long long int
const int maxn=1e5+10;
int n,m;
struct node{
int l,r;
ll sum;
}t[maxn<<2];
ll lazy[maxn<<2];
void down(int rt){
if(lazy[rt]){
ll tmp=lazy[rt];
lazy[rt<<1]|=tmp,lazy[rt<<1|1]|=tmp;
t[rt<<1].sum|=tmp,t[rt<<1|1].sum|=tmp;
lazy[rt]=0;
}
}
void build(int rt,int l,int r){
t[rt].l=l,t[rt].r=r;
t[rt].sum=0,lazy[rt]=0;
if(l==r){
return ;
}
int mid=(l+r)>>1;
build(lson),build(rson);
}
void update(int rt,int l,int r,int k){
if(l<=t[rt].l&&r>=t[rt].r){
lazy[rt]|=1ll<<k;
t[rt].sum|=1ll<<k;
return ;
}
down(rt);
int mid=(t[rt].l+t[rt].r)>>1;
if(l<=mid) update(rt<<1,l,r,k);
if(r>mid) update(rt<<1|1,l,r,k);
t[rt].sum=t[rt<<1].sum | t[rt<<1|1].sum;
}
ll query(int rt,int l,int r){
if(l<=t[rt].l&&r>=t[rt].r) return t[rt].sum;
down(rt);
int mid=(t[rt].l+t[rt].r)>>1;
ll ans=0;
if(l<=mid) ans|=query(rt<<1,l,r);
if(r>mid) ans|=query(rt<<1|1,l,r);
return ans;
}
更新节点,区间合并(push_up)
//操作:去掉和加上该点,求包括该点的最长连续区间长度
int n,m;
struct node{
int l,r;
int lsum; //从该点向左,共有lsum个连续区间
int rsum; //从该点向右,共有rsum个连续区间
int sum; //该点连续区间长度
}t[maxn<<2];
int lazy[maxn<<2];
stack <int> s;
void up(int rt,int l,int r){
t[rt].lsum=t[rt<<1].lsum;
t[rt].rsum=t[rt<<1|1].rsum;
int mid=(l+r)>>1;
if(t[rt].lsum==mid-l+1) t[rt].lsum+=t[rt<<1|1].lsum;
if(t[rt].rsum==r-mid ) t[rt].rsum+=t[rt<<1].rsum;
t[rt].sum=max(t[rt<<1].rsum+t[rt<<1|1].lsum,max(t[rt<<1].sum,t[rt<<1|1].sum));
}
void build(int rt,int l,int r){
t[rt].l=l,t[rt].r=r;
t[rt].sum=t[rt].lsum=t[rt].rsum=r-l+1;
if(l==r) return ;
int mid=(l+r)>>1;
build(lson),build(rson);
}
void update(int rt,int x,int k){ //0是破坏
if(t[rt].l==t[rt].r){
t[rt].sum=t[rt].lsum=t[rt].rsum=k;
return ;
}
int mid=(t[rt].l+t[rt].r)>>1;
if(x<=mid) update(rt<<1,x,k);
else update(rt<<1|1,x,k);
up(rt,t[rt].l,t[rt].r);
}
int query(int rt,int x){
if(t[rt].l==t[rt].r || t[rt].sum==0 || t[rt].sum==t[rt].r-t[rt].l+1)//叶子节点或者该访问区间为空或者已满
return t[rt].sum;
int mid=(t[rt].l+t[rt].r)>>1;
if(x<=mid){
if(x>=t[rt<<1].r-t[rt<<1].rsum+1)
return query(rt<<1,x)+query(rt<<1|1,mid+1);
else
return query(rt<<1,x);
}
else{
if(x<=t[rt<<1|1].l+t[rt<<1|1].lsum-1)
return query(rt<<1|1,x)+query(rt<<1,mid);
else
return query(rt<<1|1,x);
}
}
区间合并(up and down)
int n,m;
struct node{
int l,r;
int lsum; //从该区间最左端开始(到右端点)共有lsum个连续空房间
int rsum; //从该区间最右端开始(到左端点)共有rsum个连续空房间
int sum; //该区间最多有sum个连续空房间
}t[maxn<<2];
int lazy[maxn<<2];
void down(int rt){
if(lazy[rt]!=-1){
lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
if(lazy[rt]){ //1住满,该区间无空房间
t[rt<<1].lsum=t[rt<<1].rsum=t[rt<<1].sum=0;
t[rt<<1|1].lsum=t[rt<<1|1].rsum=t[rt<<1|1].sum=0;
}
else{ //0全搬走,空房间数传给子树
t[rt<<1].lsum=t[rt<<1].rsum=t[rt<<1].sum=t[rt<<1].r-t[rt<<1].l+1;
t[rt<<1|1].lsum=t[rt<<1|1].rsum=t[rt<<1|1].sum=t[rt<<1|1].r-t[rt<<1|1].l+1;
}
lazy[rt]=-1;
}
}
void up(int rt,int l,int r){
t[rt].lsum=t[rt<<1].lsum;
t[rt].rsum=t[rt<<1|1].rsum;
int mid=(l+r)>>1; //若左子树全空,加上右子树的空房间
if(t[rt].lsum==mid-l+1) t[rt].lsum+=t[rt<<1|1].lsum;
if(t[rt].rsum==r-mid ) t[rt].rsum+=t[rt<<1].rsum; //左,右,还是中间部分最大
t[rt].sum=max(t[rt<<1].rsum+t[rt<<1|1].lsum,max(t[rt<<1].sum,t[rt<<1|1].sum));
}
void build(int rt,int l,int r){
t[rt].l=l,t[rt].r=r;
t[rt].sum=t[rt].lsum=t[rt].rsum=r-l+1; //开始都是空房
lazy[rt]=-1;
if(l==r){
return ;
}
int mid=(l+r)>>1;
build(lson),build(rson);
}
void update(int rt,int l,int r,int k){
if(l<=t[rt].l&&r>=t[rt].r){
lazy[rt]=k;
if(k)
t[rt].sum=t[rt].lsum=t[rt].rsum=0; //1的话住进来,该区间没有空房间
else
t[rt].sum=t[rt].lsum=t[rt].rsum=r-l+1;
return ;
}
down(rt);
int mid=(t[rt].l+t[rt].r)>>1;
if(mid>=r) update(rt<<1,l,r,k);
else if(mid+1<=l) update(rt<<1|1,l,r,k);
else{
update(rt<<1,l,mid,k);
update(rt<<1|1,mid+1,r,k);
} //区间合并一定要这么写
up(rt,t[rt].l,t[rt].r);
}
int query(int rt,int l,int r,int d){ //找最左边位置,分别从左,中间,右找
if(l==r)
return l;
int mid=(l+r)>>1;
down(rt);
if(t[rt<<1].sum>=d)
return query(rt<<1,l,mid,d);
else if(t[rt<<1].rsum+t[rt<<1|1].lsum>=d)
return mid-t[rt<<1].rsum+1;
else
return query(rt<<1|1,mid+1,r,d);
}