bzoj4237稻草人
写了一中午,被自己瓜得无话可说。
cdq的题,然后开始脑补。
写了第一个版本是考虑一半对另一半的贡献,贡献的那一遍维护单调性,没有考虑查询的一半的点之间的影响,一直偏大,14pt。
卡掉的数据:
5
1 5
5 4
2 1
3 2
4 3
然后不知道如何脑抽地写了第二个版本,树状数组乱搞,从挡住的地方往上在数组数组里减,然后被重复挡的部分会被多减,一直偏小,31pt
卡掉的数据
5
1 1
4 2
2 3
5 4
5 5
最终屈服于题解,,智商堪忧,,
按x排序,按y分治,考虑下一半对上一半的影响,上一半维护单增的单调栈,相当于知道这个查询点前一个挡住它的点的位置pos,从该点往后的单减的栈就是答案。
于是下一半维护单减的栈,二分找到其中第一个x大于pos的x的位置,往后的栈大小就是答案。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<cmath>
const int N=2e5+7;
typedef long long LL;
using namespace std;
int n,xx[N],yy[N],q1[N],q2[N],top1,top2;
LL ans;
template<typename T> void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
struct node{
int x,y;
friend bool operator <(const node&A,const node &B) {
return A.x<B.x;
}
}p[N],tp[N];
int ef(int x) {
int l=1,r=top1,res=0;
while(l<=r) {
int mid=((l+r)>>1);
if(p[q1[mid]].x>x) res=mid,r=mid-1;
else l=mid+1;
}
if(res!=0) res=top1-res+1;
return res;
}
void cdq(int l,int r) {
if(l==r) return;
int mid=((l+r)>>1),ql=l-1,qr=mid;
top1=top2=0;
for(int i=l;i<=r;i++) {
if(p[i].y<=mid) {
tp[++ql]=p[i];
while(top1&&p[q1[top1]].y<p[i].y) top1--;
q1[++top1]=i;
}
else {
tp[++qr]=p[i];
while(top2&&p[q2[top2]].y>p[i].y) top2--;
ans+=ef(p[q2[top2]].x);
q2[++top2]=i;
}
}
for(int i=l;i<=r;i++) p[i]=tp[i];
cdq(l,mid); cdq(mid+1,r);
}
#define DEBUG
int main() {
#ifdef DEBUG
freopen("scarecrows.in","r",stdin);
freopen("scarecrows.out","w",stdout);
#endif
read(n);
for(int i=1;i<=n;i++) {
read(p[i].x); read(p[i].y);
xx[i]=p[i].x;
yy[i]=p[i].y;
}
sort(xx+1,xx+n+1);
sort(yy+1,yy+n+1);
for(int i=1;i<=n;i++) {
p[i].x=lower_bound(xx+1,xx+n+1,p[i].x)-xx;
p[i].y=lower_bound(yy+1,yy+n+1,p[i].y)-yy;
}
sort(p+1,p+n+1);
cdq(1,n);
printf("%lld\n",ans);
return 0;
}
不管怎么说,bzojSolved数终于突破两位数了,留恋一下,可喜可贺可喜可贺。