果然考试时候写题乱脑子,代码写的又臭又长。
首先五个点其实是找三个点V字形的,然后f[i]表示以i为结尾的V的个数,其实就是所有i左边纵坐标比i小的数中前面纵坐标比i大的数的个数,说起来好麻烦,意会即可。
第一眼感觉是树套树可做。
后来想了想,弃疗了。
先不考虑相等的情况。
果断想一想离线算法,按照纵坐标排序,从小到大插入数列中,每个点i维护一个data[i]表示未插入序列中横坐标小于i的数的个数,那么f[j]就等于1到j-1中所有已插入的data之和,为什么呢?因为现在在未插入数列中的数都是大于j的纵坐标的。然后每次插入j,就把j+1到n的所有data全部-1,注意赋初始值的时候的处理。
考虑上相等的情况果断炸了。
横坐标可以相等,纵坐标可以相等。
代码真心没法看。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #define maxn 100010 #define mod 1000000007 using namespace std; struct yts { int l,r,data,tag,len; }t[4*maxn]; struct yts1 { int x,y,id,x1; }p[maxn]; int n; int f[maxn][2]; bool cmp(yts1 x,yts1 y) { return x.x<y.x; } bool cmpp(yts1 x,yts1 y) { return x.x>y.x; } bool cmp1(yts1 x,yts1 y) { return x.id<y.id; } bool cmp2(yts1 x,yts1 y) { return x.id>y.id; } bool cmp3(yts1 x,yts1 y) { return x.y<y.y; } void update(int i) { if (t[i].l==t[i].r) return; t[i].len=t[i*2].len+t[i*2+1].len; t[i].data=0; if (t[i*2].len) t[i].data=(t[i].data+t[i*2].data)%mod; if (t[i*2+1].len) t[i].data=(t[i].data+t[i*2+1].data)%mod; } void push(int i,int x) { t[i].data=(t[i].data+t[i].len*x)%mod; t[i].tag=(t[i].tag+x)%mod; } void release(int i) { if (t[i].l==t[i].r) return; if (!t[i].tag) return; push(i*2,t[i].tag);push(i*2+1,t[i].tag); t[i].tag=0; } void build(int i,int l,int r) { t[i].l=l;t[i].r=r; t[i].tag=0;t[i].data=0;t[i].len=0; if (l==r) return; int mid=(l+r)/2; build(i*2,l,mid);build(i*2+1,mid+1,r); } void modify1(int i,int x,int d) { if (t[i].l==t[i].r) {t[i].len=1;t[i].data=(t[i].tag+d)%mod;return;} release(i); int mid=(t[i].l+t[i].r)/2; if (x<=mid) modify1(i*2,x,d); else modify1(i*2+1,x,d); update(i); } void modify2(int i,int l,int r,int x) { if (l>r) return; if (l<=t[i].l && t[i].r<=r) {push(i,x);return;} release(i); int mid=(t[i].l+t[i].r)/2; if (l<=mid) modify2(i*2,l,r,x); if (mid<r) modify2(i*2+1,l,r,x); update(i); } int query(int i,int l,int r) { if (!t[i].len) return 0; if (l<=t[i].l && t[i].r<=r) return t[i].data; release(i); int mid=(t[i].l+t[i].r)/2; int ans=0; if (l<=mid) ans+=query(i*2,l,r); if (mid<r) ans+=query(i*2+1,l,r); return ans; } void solve0() { sort(p+1,p+n+1,cmp3); build(1,1,n); for (int i=1;i<=n;i++) { int j=i; while (j<n && p[j+1].y==p[i].y) j++; for (int k=i;k<=j;k++) modify2(1,p[k].x1,n,-1); for (int k=i;k<=j;k++) f[p[k].id][0]=query(1,1,p[k].x-1); for (int k=i;k<=j;k++) modify1(1,p[k].id,p[k].x-1); i=j; } } void solve1() { sort(p+1,p+n+1,cmp3); build(1,1,n); for (int i=1;i<=n;i++) { int j=i; while (j<n && p[j+1].y==p[i].y) j++; for (int k=i;k<=j;k++) modify2(1,1,p[k].x-1,-1); for (int k=i;k<=j;k++) f[p[k].id][1]=query(1,p[k].x1,n); for (int k=i;k<=j;k++) modify1(1,p[k].id,n-p[k].x1+1); i=j; } } int main() { //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y); sort(p+1,p+n+1,cmp); int mx=1;p[1].x1=1; for (int i=2;i<=n;i++) { if (p[i].x!=p[i-1].x) mx=i; p[i].x1=mx; } for (int i=1;i<=n;i++) p[i].x=p[i].x1; p[n].x1=n+1; for (int i=n-1;i>=1;i--) { if (p[i].x!=p[i+1].x) p[i].x1=p[i+1].x; else p[i].x1=p[i+1].x1; } for (int i=1;i<=n;i++) p[i].id=i; solve0(); solve1(); long long ans=0; for (int i=1;i<=n;i++) ans=(ans+(long long)f[i][0]*f[i][1]%mod)%mod; printf("%lld\n",ans); return 0; }