1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #define ll long long 5 #define P 2147483648LL 6 using namespace std; 7 int n,m,w,K,H[200001]; 8 ll c[100001][11],tr[200001],ans; 9 struct data{int x,y;}a[100005]; 10 int h[200001],l[200001]; 11 int now[200001]; 12 int find(int x) 13 { 14 int l=1,r=2*w,mid; 15 while(l<=r) 16 { 17 int mid=(l+r)>>1; 18 if(H[mid]<x)l=mid+1; 19 else if(H[mid]>x)r=mid-1; 20 else return mid; 21 } 22 } 23 void getc() 24 { 25 c[0][0]=1; 26 for(int i=1;i<=w;i++) 27 {c[i][0]=1; 28 for(int j=1;j<=min(K,i);j++) 29 c[i][j]=(c[i-1][j]+c[i-1][j-1])%P; 30 } 31 } 32 int lowbit(int x){return x&(-x);} 33 void update(int x,int y) 34 { 35 while(x<=2*w) 36 { 37 tr[x]+=y;tr[x]%=P; 38 x+=lowbit(x); 39 } 40 } 41 ll ask(int x) 42 { 43 ll s=0; 44 while(x) 45 { 46 s+=tr[x];s%=P; 47 x-=lowbit(x); 48 } 49 return s; 50 } 51 inline bool cmp(data a,data b) 52 { 53 if(a.y==b.y)return a.x<b.x; 54 return a.y<b.y; 55 } 56 int main() 57 { 58 scanf("%d%d%d",&m,&n,&w); 59 for(int i=1;i<=w;i++) 60 { 61 scanf("%d%d",&a[i].x,&a[i].y); 62 H[2*i-1]=a[i].x; 63 H[2*i]=a[i].y; 64 } 65 scanf("%d",&K);getc(); 66 sort(H+1,H+2*w+1); 67 for(int i=1;i<=w;i++) 68 { 69 h[find(a[i].y)]++; 70 l[find(a[i].x)]++; 71 } 72 sort(a+1,a+w+1,cmp); 73 int lf; 74 for(int i=1;i<=w;i++) 75 { 76 if(i>1&&a[i].y==a[i-1].y) 77 { 78 lf++; 79 ll t1=ask(find(a[i].x)-1)-ask(find(a[i-1].x)); 80 ll t2=c[lf][K]*c[h[find(a[i].y)]-lf][K]; 81 ans+=t1*t2; 82 ans%=P; 83 } 84 else lf=0; 85 int d=find(a[i].x);now[d]++; 86 int change=(c[now[d]][K]*c[l[d]-now[d]][K]-c[now[d]-1][K]*c[l[d]-now[d]+1][K])%P; 87 update(d,change); 88 } 89 if(ans<0)ans+=P; 90 printf("%d",ans); 91 return 0; 92 }
树状数组,预处理出每一行 每一列的坟墓数 将坐标按x,y排序。一行一行扫,用树状数组存一段区间上下方案数相乘,按顺序扫时,能顺便求出左右,这样再乘上这段区间的树状数组
即可。树状数组修改时先减去原值,在加。