链接
http://www.lydsy.com/JudgeOnline/problem.php?id=3110
题解
惊!我突然明白
SDOI2017Day2T3
我为什么怒丢30分了,这道题里刚开始犯了同样的错误,虽然我正确处理了区间赋值和区间加的先后,但是我外面在打赋值标记的时候并没有将加标记清零。
这题啊,就是整体二分啊。
你就二分一个答案
mid
,然后顺着扫一遍,把
c≥mid
的操作在线段树的对应区间上加
1
<script type="math/tex" id="MathJax-Element-195">1</script>。每个查询看看,如果加多了就说明答案需要更大,否则答案需要更小。分治下去就行了。
代码
//整体二分+线段树
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#define maxn 50005
#define ll long long
using namespace std;
ll N, M, ndtot, ans[maxn];
struct opt{ll type, a, b, c, id;}o[maxn];
vector<opt> v;
struct segtree
{
segtree *ch[2];
ll l, r, sum, set, add, ans;
}pool[maxn<<2], *root;
void pushdown(segtree *p)
{
if(p->set)
{
p->sum=0;
if(p->ch[0])
p->ch[0]->set=p->ch[1]->set=1,
p->ch[0]->add=p->ch[1]->add=0;
p->set=0;
}
if(p->add)
{
p->sum+=(p->r-p->l+1)*p->add;
if(p->ch[0])p->ch[0]->add+=p->add, p->ch[1]->add+=p->add;
p->add=0;
}
}
void pushup(segtree *p)
{
if(!p->ch[0])return;
pushdown(p->ch[0]), pushdown(p->ch[1]);
p->sum=p->ch[0]->sum+p->ch[1]->sum;
}
void segadd(segtree *p, ll l, ll r)
{
pushdown(p);
ll mid=p->l+p->r>>1;
if(l<=p->l and r>=p->r){p->add++;return;}
if(l<=mid)segadd(p->ch[0],l,r);
if(r>mid)segadd(p->ch[1],l,r);
pushup(p);
}
ll segsum(segtree *p, ll l, ll r)
{
pushdown(p);
int ans=0, mid=p->l+p->r>>1;
if(l<=p->l and r>=p->r)return p->sum;
if(l<=mid)ans+=segsum(p->ch[0],l,r);
if(r>mid)ans+=segsum(p->ch[1],l,r);
return ans;
}
void build(segtree *p, ll l, ll r)
{
ll mid=l+r>>1;
p->l=l, p->r=r;
if(l==r)return;
build(p->ch[0]=pool+ ++ndtot,l,mid);
build(p->ch[1]=pool+ ++ndtot,mid+1,r);
}
void solve(ll l, ll r, vector<opt> &lis)
{
ll mid=ceil((l+r)/2.0), i, tmp;
vector<opt> lis1, lis2;
vector<opt>::iterator it;
if(l==r)
{
for(it=lis.begin();it!=lis.end();it++)ans[it->id]=mid;
return;
}
root->set=1;
root->add=0;
for(it=lis.begin();it!=lis.end();it++)
{
if(it->type==1 and it->c>=mid)
segadd(root,it->a,it->b), lis2.push_back(*it);
if(it->type==1 and it->c<mid)lis1.push_back(*it);
if(it->type==2)
{
tmp=segsum(root,it->a,it->b);
if(tmp>=it->c)lis2.push_back(*it);
else it->c-=tmp, lis1.push_back(*it);
}
}
solve(l,mid-1,lis1);
solve(mid,r,lis2);
}
ll read(ll x=0)
{
char c=getchar(); bool f=0;
while(c<48 or c>57)f=f or c=='-', c=getchar();
while(c>=48 and c<=57)x=(x<<1)+(x<<3)+c-48, c=getchar();
return f?-x:x;
}
void init()
{
ll a, b, c, i;
N=read(), M=read();
for(i=1;i<=M;i++)o[i].type=read(), o[i].a=read(), o[i].b=read(), o[i].c=read(),
o[i].id=i;
build(root=pool+ ++ndtot,1,N);
for(i=1;i<=M;i++)
{
if(o[i].type==1)segadd(root,o[i].a,o[i].b);
else o[i].c=min(o[i].c,segsum(root,o[i].a,o[i].b));
}
for(i=1;i<=M;i++)v.push_back(o[i]);
}
int main()
{
init();
solve(-N,N,v);
for(int i=1;i<=M;i++)if(o[i].type==2)printf("%lld\n",ans[i]);
return 0;
}