https://vjudge.net/contest/240755#problem/D
线段树
一:建树 正向设0,反调设置C的数值,每个节点的C值=两子节点C值的最小值
二.区域更新值
1.e[o].l==l&&e[o].r==r时代表叶子节点和整个节点全部在l和r的范围之内
C>1时,只更新此时的C--,add++;
2.叶节点不满足第一种情况时,必定要更新此时的节点
sum++;
3.下掉此时的add值,add=0;
4.回溯此时的sum值和C值
三。查询
跟随这查询路线更新一下add值
此时每个节点的sum值都不会变
线段树考的递归和回调比较多
另外查询的l,r值可变可不变
(add(mid+1,r))
我的是变化的
#include<iostream>
#include<cstdio>
using namespace std;
#include<algorithm>
#define Max 100000
struct tree
{
int l,r;
int c;当c为0的时候,更新
int sum;结果值
int add;//个数
}e[Max*4+10];
int b[Max+10];
void build(int l,int r,int o)
{
e[o].l=l;
e[o].r=r;
e[o].sum=0;
e[o].add=0;
if(l==r)
{
e[o].c=b[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,o*2);
build(mid+1,r,o*2+1);
e[o].c=min(e[o*2].c,e[o*2+1].c);
}
void add(int l,int r,int o)
{
if(e[o].l==l&&e[o].r==r&&e[o].c>1)
{
e[o].add+=1;
e[o].c-=1;
return ;
}
if(e[o].l==e[o].r)
{
e[o].add+=1;
e[o].c-=1;
if(e[o].c<=0)
{
e[o].sum+=1;
e[o].c=b[e[o].l];
}
return;
}
e[o*2].c-=e[o].add;
e[o*2].add+=e[o].add;
e[o*2+1].c-=e[o].add;
e[o*2+1].add+=e[o].add;
e[o].add=0;
int mid=(e[o].l+e[o].r)>>1;
if(mid>=r)
{
add(l,r,o*2);
}
else if(mid+1<=l)
{
add(l,r,o*2+1);
}
else
{
add(l,mid,o*2);
add(mid+1,r,o*2+1);
}
e[o].c=min(e[o*2].c,e[o*2+1].c);
e[o].sum=e[o*2].sum+e[o*2+1].sum;
}
int query(int l,int r,int o)
{
if(e[o].l==l&&e[o].r==r)
{
return e[o].sum;
}
e[o*2].add+=e[o].add;
e[o*2].c-=e[o].add;
e[o*2+1].add+=e[o].add;
e[o*2+1].c-=e[o].add;
e[o].add=0;
int mid=(e[o].l+e[o].r)>>1;
int res;
if(r<=mid)
{
res= query(l,r,o*2);
}
else if(mid+1<=l)
{
res= query(l,r,o*2+1);
}
else
{
res= query(l,mid,o*2)+query(mid+1,r,o*2+1);
}
e[o].sum=e[o*2].sum+e[o*2+1].sum;
e[o].c=min(e[o*2].c,e[o*2+1].c);
return res;
}
int main()
{
int n,q;
while(scanf("%d%d",&n,&q)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
}
string sh;
build(1,n,1);
for(int i=0;i<q;i++)
{
cin>>sh;
int x,y;
if(sh=="add")
{
cin>>x>>y;
add(x,y,1);
}
else if(sh=="query")
{
cin>>x>>y;
cout<<query(x,y,1)<<endl;
}
}
}
}