Luogu8251 solution
Problem
link->https://www.luogu.com.cn/problem/P8251。
Solution
这道题我考场上最后 \(10\) 分钟想出正解,然而在考试完后的 \(10\) 分钟才打出代码。。。
可以发现,无论什么情况,下标大的二元组总是在下标小的二元组的上面,也就是说,如果一个二元组它不是“完美的”,那么它一定是被一个下标小于它的二元组所堵住。
由于 \(l\) 到 \(r\) 是依次入栈的,那么如果一个二元组不是完美的,那么它只可能被一个唯一确定的二元组挡住。
那么,我们可以先求出,如果在区间为 \([1,1]\) 状态下,每个二元组是被哪个二元组所挡住的,记为 \(f_i\)(\(f_i=0\),则它是“完美的”)。
stack<int> s;
_for(i,1,n) { //循环宏,定义见完整代码
while(!s.empty()&&!(a[s.top()]!=a[i]&&b[i]<b[s.top()])) s.pop();
if(!s.empty()) f[i]=s.top();
//printf("f[%d] = %d\n",i,f[i]);
s.push(i);
}
为什么上述代码正确地求出 \(f_i\) 呢?我们不妨来用反证法证明一下:
设 \(x\) 同样能挡住 \((a_i,b_i)\)(是最优的 \(f_i\)),但是 \(x\) 一定在 \(f_i\) 之下,而 \(f_i\) 一定能挡住 \((a_i,b_i)\),故 \(f_i\) 在 \(x\) 之前就能挡住 \((a_i,b_i)\),是最优的 \(f_i\)。
容易看出,在 \([l,r]\) 区间中,如果下标为 \(i\) 的二元组 \((a_i,b_i)\),是完美的,当且仅当 \(f_i<l\),即唯一确定挡住它的二元组不在 \([l,r]\) 区间内。
while(q--) {
int l,r;
read(l,r); //快读,定义见完整代码
int ans=0;
_for(i,l,r)
if(f[i]<l)
++ans;
printf("%d\n",ans);
}
不过,上述代码时间复杂度在最坏情况任是 \(\Theta(nm)\),无法通过此题。
我们不妨先看看现在的问题:
给定无序数组 \(\{f_n\}\),进行 \(m\) 次每次给定 \(l,r\) 问有多少个 \(f_i<l\) 且 \(l\le i\le r\)。
看见有很多大佬用主席树在线查询的,蒟蒻我不禁瑟瑟发抖。
我们设为 \(f(l,r,k)\) 为满足 \(f_i<k\) 且 \(l\le i\le r\) 的 \(f_i\) 数量,那么运用一些前缀和的思想,可以看出 \(f(l,r,l)=f(1,r,l)-f(1,l,l)+1\)。
对于所有的 \(f(1,r,k)\) 我们均可以使用树状数组以 \(\Theta(n\log{n})\) 的时间复杂度一次性计算出来。
这样,我们不妨离线处理出每个 \(f(1,r,l)\) 和 \(f(1,l,l)\),最后回答即可。
Code
#include<bits/stdc++.h>
#define pd push_back
#define pb pop_back
#define mk make_pair
#define LL long long
#define PII pair<int,int>
#define _for(a,b,c) for(int a=b;a<=c;a++)
#define _rep(a,b,c) for(int a=b;a>=c;a--)
using namespace std;
template <typename T> inline void read(T& x) {
x=0; T f=1;
char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch&15); ch=getchar(); }
x=x*f;
return;
}
template <typename T,typename ...Arg> inline void read(T& x,Arg& ...arg){
read(x); read(arg...);
}
int power(int a,int b) {
int ans=1;
do {
if(b&1) ans*=a; a*=a;
} while(b>>=1);
return ans;
}
const int N=5e5+5;
int a[N],b[N],f[N],n,q;
int tree[N],ans[N];
struct node {
int l,r,id;
}; node que[N];
bool cmp1(node x,node y) {
return x.l<y.l;
}
bool cmp2(node x,node y) {
return x.r<y.r;
}
int lowbit(int x) { return x&-x; }
void Add(int x,int k) {
while(x<=n)
tree[x]+=k,x+=lowbit(x);
}
int Query(int x) {
int sum=0;
while(x)
sum+=tree[x],x-=lowbit(x);
return sum;
}
int main() {
// freopen("stack.in","r",stdin);
// freopen("stack.out","w",stdout);
read(n,q);
_for(i,1,n)
read(a[i]);
_for(i,1,n)
read(b[i]);
stack<int> s;
_for(i,1,n) {
while(!s.empty()&&!(a[s.top()]!=a[i]&&b[i]<b[s.top()])) s.pop();
if(!s.empty()) f[i]=s.top();
//printf("f[%d] = %d\n",i,f[i]);
s.push(i);
}
_for(i,1,q) {
int l,r;
read(l,r);
que[i]=node{l,r,i};
}
sort(que+1,que+q+1,cmp1);
int k=1;
_for(i,1,n) {
Add(f[i]+1,1);
//printf("f[%d]=%d++\n",i,f[i]);
while(i==que[k].l) {
//printf("%d %d %d\n",que[k].l,que[k].r,que[k].id);
ans[que[k].id]-=Query(que[k].l),++k;
}
}
sort(que+1,que+q+1,cmp2);
memset(tree,0,sizeof(tree));
k=1;
_for(i,1,n) {
Add(f[i]+1,1);
//printf("f[%d]=%d++\n",i,f[i]);
while(i==que[k].r) {
//printf("%d %d %d\n",que[k].l,que[k].r,que[k].id);
ans[que[k].id]+=Query(que[k].l),++k;
}
}
_for(i,1,q)
printf("%d\n",ans[i]+1);
return 0;
}

浙公网安备 33010602011771号