题意:
今天停电了,阅览室里的大家陷入了无电可用的状态,F发现他们桌子用的备用电源还在工作,于是大家就顺着这个备用电源用插线板连起了一条长链。
容易看出插线板的结构会形成一棵树(一个插线板所插在的插线板记为它的父节点,根节点为备用电源),但是大家不会把自己的插线板一直放在阅览室里(离开的时候就带走了),因此会出现树结构中某个节点消失的情况,而之后对树结构的修复方案很多会导致大家的混乱。因此F决定把插线板摆成一条链。F收集了所有带插线板来阅览室的同学的情况,把这些插线板排成了一条链并把它们从小到大编号,i号插线板会在第Li个时刻被一个来阅览室的同学带来,在第Ri个时刻拿走。我们规定0号插线板为备用电源(显然电源是一直可用的)。
当一个插线板被带来的时候,它会插到它左面的相邻插线板上,而它右面相邻的插线板会插到它上。当一个插线板被带走的时候,它右面相邻的插线板会插到它左面相邻的插线板上。也就是说这两种行为都会导致右面的插线板的插头的移动。这种移动会导致接在这个插线板的用电器也需要配合移动。(其他插线板和用电器不会受到影响)
F也收集了所有要用电的同学的情况。有Q个用电的同学想询问,如果他们在 [L,R] 的时刻用电,那么选择哪个插线板可以最小化他们用电器的移动次数。
虽然电源被我们看成0号插线板但是用电器不能接在备用电源上,即使此时一个插线板都没有也不行。
题解:
忽略边界条件吧, 大概就是有
n" role="presentation" style="position: relative;">n个集合,每个集合里面有一些
[li,ri]" role="presentation" style="position: relative;">[li,ri]的数,每次询问
L,R" role="presentation" style="position: relative;">L,R ,求
li≤L,R≤ri" role="presentation" style="position: relative;">li≤L,R≤ri的集合中
[L,R]" role="presentation" style="position: relative;">[L,R]的数的个数的最小值。
可以分块来做, 先处理出 询问为
[i∗N,j]" role="presentation" style="position: relative;">[i∗N‾‾√,j]的答案, 注意因为要求最小值,我们可以在询问的时候先询问包含
L,R" role="presentation" style="position: relative;">L,R的大区间的最小值, 再往内部挪动, 这样如果有比原来的最小值更优的值一定会在挪动的时候更新。
(同理最大值只需要先求小区间再往外挪动)
最后注意在挪动的时候要把那些
li≤L" role="presentation" style="position: relative;">li≤L的区间给算进来,我们还需要用一个可持久化数组。 直接每个前缀记
N" role="presentation" style="position: relative;">N‾‾√个
int" role="presentation" style="position: relative;">int数组的指针,每次复制前面的指针并复制一块新的数组来修改即可。
时间复杂度
O(nn)" role="presentation" style="position: relative;">O(nn‾√)
#include
using namespace std;
const int RLEN=1<<18|1, N=1e5+50, B=333, INF=0x3f3f3f3f;
typedef set <int> Set;
typedef Set ::iterator it_s;
typedef pair<int,int> pii;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob)?(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin)):0;
return (ib==ob)?-1:*ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch==-1) return 0; if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
int n,m,q,type,tot,a[N],b[N],L[N],R[N],sum[N],res[N/B+2][N],lst;
pii c[N];
struct BL {
int *s[N/B+2];
inline void add(int x) {
int k=x/B, p=x%B;
int *t=(int *)malloc(sizeof(int)*B);
if(s[k]==NULL) memset(t,0,sizeof(int)*B);
else memcpy(t,s[k],sizeof(int)*B);
++t[p]; s[k]=t;
}
inline int ask(int x) {
return (s[x/B]==NULL)?0:s[x/B][x%B];
}
}pre[N];
Set S;
int main() {
n=rd(), m=rd(), q=rd(), type=rd();
for(int i=1;i<=n;i++) {
L[i]=rd(), R[i]=rd();
a[L[i]]=i; a[R[i]]=-i;
c[++tot]=pii(L[i],i);
c[++tot]=pii(R[i],-i);
}
sort(c+1,c+tot+1);
for(int i=1;i<=tot;i++) {
it_s t=S.upper_bound(abs(c[i].second));
if(t!=S.end()) b[c[i].first]=*t;