【XSY2762】插线板 分块
题目大意
有\(n\)个插线板,每个插线板会在\(l_i\)时刻初插入到队列中(队列是按插线板的编号排序的),\(r_i\)时刻末移除。
插入一个插线板时会对当前所有接在队列中这个插线的下一个插线板上的用电器造成\(1\)的代价。
有\(q\)个询问,每次给你\(x,y\),问你你要在\(x\)时刻把用电器接在插线板上,\(y\)时刻移除,最少的代价是多少。
\(n,q\leq 50000\)
题解
先处理每个时刻那个插线板上的用电器得到了\(1\)的代价。这个东西的总和是\(O(n)\)的。
可以用分块在\(O(n\sqrt n)\)内预处理,\(O(1)\)查询如果把用电器接在一个插线板上,那么代价是多少。
按时间分块,预处理出每一块的左端点到右边任意一个点的答案。
可以枚举左端点然后从最右边往左扫一遍,维护当前的最小值。
那么对于一个询问\(x,y\),找到包含这个询问左端点的块的左端点\(l\),那么答案只有可能是三种情况:
1.询问\([l,y]\)的答案,这个已经处理好了。
2.插到一个在\([l,x]\)中有修改的插线板上。
3.插到一个在\([l,x]\)中插入的插线板上。
暴力统计即可。
取块大小\(size=\sqrt n\)可以得到最优时间复杂度\(O((n+q)\sqrt n)\)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<utility>
using namespace std;
int rd()
{
int s,c;
while((c=getchar())<'0'||c>'9');
s=c-'0';
while((c=getchar())>='0'&&c<='9')
s=s*10+c-'0';
return s;
}
typedef pair<int,int> pii;
const int inf=0x3fffffff;
set<int> st;
int b1[100010];
int b2[100010];
void add(int x,int y)
{
set<int>::iterator p=st.lower_bound(x);
if(p!=st.end())
b1[y]=*p;
}
int al[100010];
int ar[100010];
pii c[100010];
const int N=100000;
const int size=500;
struct orz
{
int s1[N/size+1];
int *s2[N/size+1];
orz()
{
memset(s1,0,sizeof s1);
memset(s2,0,sizeof s2);
}
void add(int x)
{
int bl=x/size;
for(int i=bl+1;i<=N/size;i++)
s1[i]++;
int *&t=s2[bl];
if(!t)
{
t=new int[size];
for(int i=0;i<size;i++)
t[i]=0;
}
for(int i=x%size;i<size;i++)
t[i]++;
}
int query(int x)
{
int s=0;
s+=s1[x/size];
if(s2[x/size])
s+=s2[x/size][x%size];
return s;
}
};
orz bl[50010];
int sum[50010];
int s[N/size+1][100010];
int main()
{
#ifndef ONLINE_JUDGE
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
#endif
int n,m,q,type;
scanf("%d%d%d%d",&n,&m,&q,&type);
for(int i=1;i<=n;i++)
{
al[i]=rd();
ar[i]=rd();
c[al[i]]=pii(i,1);
c[ar[i]]=pii(i,2);
}
for(int i=1;i<=m;i++)
if(c[i].first)
{
b2[i]=c[i].first;
if(c[i].second==1)
{
add(c[i].first,i);
st.insert(c[i].first);
}
else
{
st.erase(c[i].first);
add(c[i].first,i);
}
}
for(int i=1;i<=m;i++)
if(b1[i])
{
if(c[i].second==1)
bl[b1[i]].add(i);
else
bl[b1[i]].add(i+1);
}
for(int i=1;i<=m;i+=size)
{
for(int j=i;j<=m;j++)
if(b1[j])
sum[b1[j]]++;
int now=inf;
for(int j=m;j>=i;j--)
{
if(c[j].second==2&&al[b2[j]]<=i)
now=min(now,sum[b2[j]]);
if(c[j].second==2&&b1[j])
{
sum[b1[j]]--;
if(al[b1[j]]<=i)
now=min(now,sum[b1[j]]);
}
s[(i-1)/size][j]=now;
if(c[j].second==1&&b1[j])
{
sum[b1[j]]--;
if(al[b1[j]]<=i)
now=min(now,sum[b1[j]]);
}
}
}
int x,y;
int last=0;
for(int i=1;i<=q;i++)
{
x=rd();
y=rd();
if(type)
{
x^=last;
y^=last;
}
int ans=s[(x-1)/size][y];
for(int j=(x-1)/size*size+1;j<=x;j++)
{
if(ar[b1[j]]>=y)
ans=min(ans,bl[b1[j]].query(y)-bl[b1[j]].query(x));
if(ar[b2[j]]>=y)
ans=min(ans,bl[b2[j]].query(y)-bl[b2[j]].query(x));
}
if(ans==inf)
ans=-1;
printf("%d\n",ans);
if(ans==-1)
last=0;
else
last=ans;
}
return 0;
}