题目大意
给定N件T-shirt,每件T-shirt有一个
N,M≤2∗105
Bi,Ci,Qi≤109
解题思路
一拿到题,我们发现一组一组的询问去做根本无从下手,复杂度根本过不去。那么我们就考虑吧所有询问一起做。
我们把所有的询问扔到一颗平衡树里面,最暴力的思想就是把T-shirt从前往后枚举,我们可以的到可以买这件T-shirt的区间,我们把这个区间的没个数减去Ci然后把平衡树重构。这样显然是会超时的,因为重构平衡树实在是太慢了……但是我们知道可持久化treap合并两个平衡树的复杂度是log的,但是要保证一颗平衡树的最小值比另一颗平衡树的最大值大。那么我们就可以把原来的平衡树分成减了Ci和没减Ci两个部分,我们想用可持久化treap合并,假定我们要保证前一部分的最小值大于后一部分的最大值,我们就可以把不符合的数先暴力加入另一颗,然后再整体合并。这复杂度会超?其实可以证明不会!
首先可持久化treap合并的复杂度是O(NlogM)是没问题的,关键是暴力插入的那一部分。那么我们就来算一下它的复杂度:
我们设后半部分(即没减Ci的部分)的最大值是a,前半部分(即减了Ci的部分)其中一个数是b,Ci表示为c。假设b要暴力插入,那么有以下几条式子:
b−c<a
可以推出:
b−c<c
即
b<2c,b2<c
什么意思?就是说没每次出现b要暴力插入时,减去的Ci至少为b2就是说最多插入log次!那么包里插入的复杂度就是O(MlogBilogM),所以总的复杂度是O((NlogM+MlogBilogM)时限是4s,完全可以跑的过!
程序
由于这题没打,附上Philipsweng的程序!
#include <cstring>
#include <algorithm>
#define fe first
#define se second
using namespace std;
const int MAXN = 200005;
typedef pair<int,int> P;
struct Node
{
int l,r,cnt,t_c,t_v;
int key,val,siz;
}T[MAXN];
struct Shirt
{
int pr,qu;
bool operator <(const Shirt &a) const
{
return qu > a.qu || qu == a.qu && pr < a.pr;
}
}A[MAXN];
int B[MAXN],root,N,M;
int Get_Rand()
{
return rand() * rand();
}
void Update(int nt)
{
T[nt].siz = T[T[nt].l].siz + T[T[nt].r].siz + 1;
}
void Mark(int nt,int t_c,int t_v)
{
if (!nt) return;
T[nt].cnt += t_c,T[nt].val += t_v;
T[nt].t_c += t_c,T[nt].t_v += t_v;
}
void Down(int nt)
{
if (!nt) return;
Mark(T[nt].l,T[nt].t_c,T[nt].t_v),Mark(T[nt].r,T[nt].t_c,T[nt].t_v);
T[nt].t_c = T[nt].t_v = 0;
}
int Merge(int a,int b)
{
if (!a || !b) return a ^ b;
Down(a),Down(b);
if (T[a].key > T[b].key)
{
T[a].r = Merge(T[a].r,b);
Update(a);
return a;
}
T[b].l = Merge(a,T[b].l);
Update(b);
return b;
}
P Split(int root,int siz)
{
if (!siz) return P(0,root);
Down(root);
if (siz <= T[T[root].l].siz)
{
P tmp = Split(T[root].l,siz);
T[root].l = tmp.se;
Update(root);
return P(tmp.fe,root);
}
P tmp = Split(T[root].r,siz - T[T[root].l].siz - 1);
T[root].r = tmp.fe;
Update(root);
return P(root,tmp.se);
}
int Min(int nt)
{
for(;T[nt].l;)
{
Down(nt);
nt = T[nt].l;
}
return nt;
}
int Max(int nt)
{
for(;T[nt].r;)
{
Down(nt);
nt = T[nt].r;
}
return nt;
}
void MoveL(int &nt)
{
if (!T[nt].l)
{
Down(nt);
int r = T[nt].r;
T[nt].r = 0;
Update(nt);
nt = r;
return;
}
static int Stk[MAXN];
int top = 0,bak = nt;
for(;nt;) Stk[++ top] = nt,Down(nt),nt = T[nt].l;
int p = Stk[top];
nt = Stk[top - 1];
if (p) T[nt].l = T[p].r,T[p].r = 0,Update(p),Update(nt);
for(;top;top --) Update(Stk[top]);
nt = bak;
}
void Insert(int &root,int nt)
{
int siz = 0;
for(int j = root;j;)
{
Down(j);
if (T[nt].val <= T[j].val) j = T[j].l; else
if (T[nt].val > T[j].val) siz += 1 + T[T[j].l].siz,j = T[j].r;
}
P cur = Split(root,siz);
root = Merge(Merge(cur.fe,nt),cur.se);
}
void Dfs(int root)
{
if (!root) return;
Down(root);
Dfs(T[root].l),Dfs(T[root].r);
}
int main()
{
scanf("%d", &N);
for(int i = 1;i <= N;i ++)
scanf("%d%d", &A[i].pr, &A[i].qu);
sort(A + 1,A + N + 1);
scanf("%d", &M);
for(int i = 1;i <= M;i ++)
scanf("%d", &B[i]);
for(int i = 1;i <= M;i ++) T[i].key = Get_Rand(),T[i].val = B[i],T[i].siz = 1;
for(int i = 1;i <= M;i ++) Insert(root,i);
for(int i = 1;i <= N;i ++)
{
int siz = 0;
for(int j = root;j;)
{
Down(j);
if (A[i].pr <= T[j].val) j = T[j].l; else
if (A[i].pr > T[j].val) siz += 1 + T[T[j].l].siz,j = T[j].r;
}
P cur = Split(root,siz);
Mark(cur.se,1,-A[i].pr);
for(int p,q;(p = Min(cur.se)) && (q = Max(cur.fe)) && T[p].val < T[q].val;)
{
MoveL(cur.se);
Insert(cur.fe,p);
}
root = Merge(cur.fe,cur.se);
}
Dfs(root);
for(int i = 1;i <= M;i ++)
printf("%d%c", T[i].cnt, i == M ? '\n' : ' ');
return 0;
}