题解 P3968 【[TJOI2014]电源插排】
SuperJvRuo
2018-11-07 15:09:09
楼上说,标算应该是线段树+```set```。我写的就是```std::set```+```std::map```+动态开点线段树。
s1维护各个空区间的左右端点,s2维护区间的长度和左端点,map记录学生对应的插排。插入时,从s2中找出最大区间长度,修改s1和s2;删除时,从s1中找出两侧的区间,修改s1和s2。查询时用动态开点线段树统计答案。
祝NOIp2018rp++!
```
#include<cstdio>
#include<cctype>
#include<utility>
#include<set>
#include<map>
#define PII std::pair<int,int>
#define IT std::set<PII>::iterator
int Read()
{
int x=0;char c=getchar();
while(!isdigit(c))
{
c=getchar();
}
while(isdigit(c))
{
x=x*10+(c&15);
c=getchar();
}
return x;
}
std::set<PII> s1;
std::set<PII> s2;
std::map<int,int> stu;
int Insert()
{
int l=s2.rbegin()->second;
int r=s2.rbegin()->second+s2.rbegin()->first-1;
int pos=(l+r+1)>>1;//坑点,记得这个加1
s2.erase(--s2.end());
s1.erase(PII(l,r));
if(l!=pos)
{
s1.insert(PII(l,pos-1));
s2.insert(PII(pos-1-l+1,l));
}
if(r!=pos)
{
s1.insert(PII(pos+1,r));
s2.insert(PII(r-pos,pos+1));
}
return pos;
}
void Erase(int pos)
{
IT back=s1.lower_bound(PII(pos,pos));
IT front=back;
--front;
int l=pos,r=pos;
if(front->second==pos-1)
{
l=front->first;
s2.erase(PII(front->second-front->first+1,front->first));
s1.erase(front);
}
if(back->first==pos+1)
{
r=back->second;
s2.erase(PII(back->second-back->first+1,back->first));
s1.erase(back);
}
s1.insert(PII(l,r));
s2.insert(PII(r-l+1,l));
}
struct seg
{
int l,r,sum;
int ch[2];
} tree[3000005];
int size=1;
void Add(int pos,int val,int L,int R,int idx)
{
if(L==R)
tree[idx].sum+=val;
else
{
int mid=(L+R)>>1;
if(pos<=mid)
{
if(!tree[idx].ch[0])
tree[idx].ch[0]=++size;
Add(pos,val,L,mid,tree[idx].ch[0]);
}
else
{
if(!tree[idx].ch[1])
tree[idx].ch[1]=++size;
Add(pos,val,mid+1,R,tree[idx].ch[1]);
}
tree[idx].sum=tree[tree[idx].ch[0]].sum+tree[tree[idx].ch[1]].sum;
}
}
int Query(int l,int r,int L,int R,int idx)
{
if(l<=L&&R<=r)
return tree[idx].sum;
else
{
int mid=(L+R)>>1;
int ans=0;
if(l<=mid)
{
if(!tree[idx].ch[0])
tree[idx].ch[0]=++size;
ans+=Query(l,r,L,mid,tree[idx].ch[0]);
}
if(r>mid)
{
if(!tree[idx].ch[1])
tree[idx].ch[1]=++size;
ans+=Query(l,r,mid+1,R,tree[idx].ch[1]);
}
return ans;
}
}
int main()
{
int n=Read(),q=Read();
s1.insert(PII(1,n));
s2.insert(PII(n,1));
int k,l,r,pos;
while(q--)
{
k=Read();
if(!k)
{
l=Read(),r=Read();
printf("%d\n",Query(l,r,1,n,1));
}
else
{
if(stu[k]==0)
{
pos=stu[k]=Insert();
Add(pos,1,1,n,1);
}
else
{
Erase(pos=stu[k]);
Add(pos,-1,1,n,1);
stu[k]=0;
}
}
}
return 0;
}
```