题目大意
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
我的做法
整体二分+线段数
二分答案,然后%¥#*&#¥
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
struct tree
{
ll sum;
int l,r;
tree *ls,*rs;
ll t1,t2;
tree()
{
sum=t2=0;
t1=-1;
l=r=0;
ls=rs=0;
}
};
tree *top;
void build(tree *&p,int l,int r)
{
p=new tree;
p->l=l;
p->r=r;
if(l==r)
return;
int mid=(l+r)>>1;
build(p->ls,l,mid);
build(p->rs,mid+1,r);
}
void addtag(tree *&p,ll t1,ll t2)
{
if(t1!=-1)
{
p->t1=t1;
p->t2=0;
p->sum=t1*(p->r-p->l+1);
}
p->t2+=t2;
p->sum+=t2*(p->r-p->l+1);
}
void downtag(tree *&p)
{
if((p->t1!=-1||p->t2)&&p->l!=p->r)
{
addtag(p->ls,p->t1,p->t2);
addtag(p->rs,p->t1,p->t2);
}
p->t1=-1;
p->t2=0;
}
void maintain(tree *&p)
{
if(p->l==p->r)
return;
p->sum=p->ls->sum+p->rs->sum;
}
void add(tree *&p,int l,int r,ll t1,ll t2)
{
if(l<=p->l&&r>=p->r)
{
addtag(p,t1,t2);
return;
}
downtag(p);
int mid=(p->l+p->r)>>1;
if(l<=mid)
add(p->ls,l,r,t1,t2);
if(r>mid)
add(p->rs,l,r,t1,t2);
maintain(p);
}
ll query(tree *&p,int l,int r)
{
if(l<=p->l&&r>=p->r)
return p->sum;
ll s=0;
downtag(p);
int mid=(p->l+p->r)>>1;
if(l<=mid)
s+=query(p->ls,l,r);
if(r>mid)
s+=query(p->rs,l,r);
return s;
}
struct p
{
int id;
int op,a,b;
ll c;
p()
{
id=op=a=b=c=0;
}
};
p a[100010],b[100010],c[100010];
int ans[100010];
int d[100010];
int n,m;
void solve(int l,int r,ll sl,ll sr)
{
if(l>r)
return;
if(sl==sr)
{
int i;
for(i=l;i<=r;i++)
ans[a[i].id]=sl;
return;
}
int l1=0,l2=0;
int sm=(sl+sr)>>1;
int i;
for(i=l;i<=r;i++)
if(a[i].op==1)
if(a[i].c>sm)
{
add(top,a[i].a,a[i].b,-1,1);
c[++l2]=a[i];
}
else
b[++l1]=a[i];
else
{
ll s=query(top,a[i].a,a[i].b);
if(a[i].c>s)
{
a[i].c-=s;
b[++l1]=a[i];
}
else
c[++l2]=a[i];
}
add(top,1,n,0,0);
int j;
for(i=l,j=1;j<=l1;i++,j++)
a[i]=b[j];
for(j=1;j<=l2;i++,j++)
a[i]=c[j];
solve(l,l+l1-1,sl,sm);
solve(l+l1,r,sm+1,sr);
}
int main()
{
int j;
scanf("%d%d",&n,&m);
build(top,1,n);
for(j=1;j<=m;j++)
{
scanf("%d%d%d%lld",&a[j].op,&a[j].a,&a[j].b,&a[j].c);
a[j].id=j;
d[j]=a[j].op;
}
solve(1,m,1,n);
for(j=1;j<=m;j++)
if(d[j]==2)
printf("%d\n",ans[j]);
return 0;
}