传送门
数据结构优化计数菜题。
题意简述:给 n n n个点问有多少个 w w w型。
w w w型的定义:
由5个不同的点组成,满足 x 1 < x 2 < x 3 < x 4 < x 5 , x 3 > x 1 > x 2 , x 3 > x 5 > x 4 x_1<x_2<x_3<x_4<x_5,x_3>x_1>x_2,x_3>x_5>x_4 x1<x2<x3<x4<x5,x3>x1>x2,x3>x5>x4
思路:
本蒟蒻的思路很奇葩。
我们把 w w w拆成两个 v v v,把 v v v按照大小排序之后就只用统计形如 213 213 213和 312 312 312的种类数并累加贡献到 2 2 2位置上,最后乘法原理。
考虑统计这个东西。
显然 1 , 2 1,2 1,2在以 3 3 3为原点的坐标系的同一象限,于是可以按照 y y y拍个序,从下往上加点,对于每个点维护再未插入的点中在该点左/右上方的点有多少个,然后对于一个点的答案就是它左/右下方所有点维护的贡献之和。
第一个东西可以用 b i t bit bit,然后第二个贡献之和可以上权值线段树。
代码:
#include
#define fi first
#define se second
#define ri register int
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int mod=1e9+7,N=2e5+5;
typedef long long ll;
int n,f[N][2],ans=0,stk[N],top,mp[N],sig=0;
struct Pot{int x,y;}a[N];
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline bool cmp(const Pot&a,const Pot&b){return a.y==b.y?a.x<b.x:a.y<b.y;}
struct Fenwick_Tree{
int bit[N];
inline int lowbit(const int&x){return x&-x;}
inline void update(int x,int v){for(ri i=x;i<=sig;i+=lowbit(i))bit[i]=add(bit[i],v);}
inline int query(int x){int ret=0;for(ri i=x;i;i^=lowbit(i))ret=add(ret,bit[i]);return ret;}
inline void clear(){
fill(bit+1,bit+sig+1,0);
for(ri i=1,pos;i<=n;++i){
pos=lower_bound(mp+1,mp+sig+1,a[i].x)-mp;
update(pos,1);
}
}
}Bit;
struct segment_tree{
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (l+r>>1)
int sum[N<<2],num[N<<2],tag[N<<2];
inline void pushup(int p){num[p]=num[lc]+num[rc],sum[p]=sum[lc]+sum[rc];}
inline void pushnow(int p,int v){if(!num[p])return;sum[p]+=num[p]*v,tag[p]+=v;}
inline void pushdown(int p){if(tag[p])pushnow(lc,tag[p]),pushnow(rc,tag[p]),tag[p]=0;}
inline void update(int p,int l,int r,int ql,int qr,int v){
if(ql>r||qr<l||!num[p])return;
if(ql<=l&&r<=qr)return pushnow(p,v);
pushdown(p);
if(qr<=mid)update(lc,l,mid,ql,qr,v);
else if(ql>mid)update(rc,mid+1,r,ql,qr,v);
else update(lc,l,mid,ql,mid,v),update(rc,mid+1,r,mid+1,qr,v);
pushup(p);
}
inline void modify(int p,int l,int r,int k,int v){
if(l==r){sum[p]+=v,++num[p];return;}
pushdown(p),k<=mid?modify(lc,l,mid,k,v):modify(rc,mid+1,r,k,v),pushup(p);
}
inline int query(int p,int l,int r,int ql,int qr){
if(ql>r||qr<l||!num[p]||!sum[p])return 0;
if(ql<=l&&r<=qr)return sum[p];
pushdown(p);
if(qr<=mid)return query(lc,l,mid,ql,qr);
if(ql>mid)return query(rc,mid+1,r,ql,qr);
return query(lc,l,mid,ql,mid)+query(rc,mid+1,r,mid+1,qr);
}
inline void clear(){memset(tag,0,sizeof(tag)),memset(sum,0,sizeof(sum)),memset(num,0,sizeof(num));}
}T;
inline void change1(){
for(ri i=1,p,pos;i<=top;++i){
pos=lower_bound(mp+1,mp+sig+1,a[p=stk[i]].x)-mp;
T.update(1,1,sig,pos+1,sig,-1),Bit.update(pos,-1);
}
for(ri i=1,p,pos;i<=top;++i){
pos=lower_bound(mp+1,mp+sig+1,a[p=stk[i]].x)-mp;
f[p][0]=T.query(1,1,sig,1,pos-1);
}
for(ri i=1,p,pos;i<=top;++i){
pos=lower_bound(mp+1,mp+sig+1,a[p=stk[i]].x)-mp;
T.modify(1,1,sig,pos,Bit.query(pos-1));
}
}
inline void change2(){
for(ri i=1,p,pos;i<=top;++i){
pos=lower_bound(mp+1,mp+sig+1,a[p=stk[i]].x)-mp;
T.update(1,1,sig,1,pos-1,-1),Bit.update(pos,-1);
}
for(ri i=1,p,pos;i<=top;++i){
pos=lower_bound(mp+1,mp+sig+1,a[p=stk[i]].x)-mp;
f[p][1]=T.query(1,1,sig,pos+1,sig);
}
for(ri i=1,p,pos;i<=top;++i){
pos=lower_bound(mp+1,mp+sig+1,a[p=stk[i]].x)-mp;
T.modify(1,1,sig,pos,Bit.query(sig)-Bit.query(pos));
}
}
inline void solve1(){
T.clear(),Bit.clear();
for(ri i=1;i<=n;++i){
stk[top=1]=i;
while(i<n&&a[i].y==a[i+1].y)++i,stk[++top]=i;
change1();
}
}
inline void solve2(){
T.clear(),Bit.clear();
for(ri i=1;i<=n;++i){
stk[top=1]=i;
while(i<n&&a[i].y==a[i+1].y)++i,stk[++top]=i;
change2();
}
}
int main(){
n=read();
for(ri i=1;i<=n;++i)mp[++sig]=a[i].x=read(),a[i].y=read();
sort(a+1,a+n+1,cmp);
sort(mp+1,mp+sig+1),sig=unique(mp+1,mp+sig+1)-mp-1;
solve1(),solve2();
for(ri i=1;i<=n;++i)ans=add(ans,mul(f[i][0],f[i][1]));
cout<<ans;
return 0;
}