【bzoj 1227】虔誠的墓主人(樹狀陣列)
阿新 • • 發佈:2019-01-11
傳送門biu~
上下左右沒有樹的墓地必然沒有虔誠度,所以將原圖離散化成一個最大為的圖。
對於每塊墓地,令在它上、下、左、右方向常青樹的數目分別為,,,。則以這個點為中心的十字架的數目是。
顯然列舉每塊墓地,時間複雜度為會TLE。那麼我們考慮在同一行,即座標相同的兩棵常青樹之間的所有墓地,它們的和值是相同的。那麼這些墓地的虔誠度之和為。採用樹狀陣列來求和。
首先預處理出每棵樹的,,,值,按行列舉每棵樹。用當前行的樹來修改樹狀陣列中 的值。每次將兩棵樹之間的貢獻加到答案裡。
Ps:因為模數特殊,可以直接用的自然溢位,最後取答案的後31位即可。
#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;
struct data{int x,y,l,r,u,d;}a[100005];
inline bool cmp(data a,data b){return a.y<b.y || a.y==b.y && a.x<b.x;}
int n,m,w,k,ans,len;
int tree[100005],b[100005],num[100005],c[100005][15];
inline void getC(int k){
for(int i=0;i<=w;++i){
c[i][0]=1;
int go=min(i,k);
for(int j=1;j<=go;++j) c[i][j]=c[i-1][j]+c[i-1][j-1];
}
}
inline void add(int x,int val){
for(int i=x;i<=len;i+=lowbit(i)) tree[i]+=val;
}
inline int search(int x){
int re=0;
for(int i=x;i;i-=lowbit(i)) re+=tree[i];
return re;
}
int main(){
scanf("%d%d%d",&n,&m,&w);
for(int i=1;i<=w;++i) scanf("%d%d",&a[i].x,&a[i].y),b[i]=a[i].x;
sort(b+1,b+w+1); len=unique(b+1,b+w+1)-b-1;
scanf("%d",&k);getC(k);
sort(a+1,a+w+1,cmp);
for(int cnt=0,y=-1,i=1;i<=w;++i){
a[i].x=lower_bound(b+1,b+len+1,a[i].x)-b;
if(a[i].y!=y) y=a[i].y,cnt=0;
a[i].l=cnt++;
a[i].d=num[a[i].x]++;
}
for(int cnt=0,y=-1,i=w;i>=1;--i){
if(a[i].y!=y) y=a[i].y,cnt=0;
a[i].r=cnt++;
a[i].u=num[a[i].x]-a[i].d-1;
}
for(int i=1;i<=w;++i){
add(a[i].x,c[a[i].u][k]*c[a[i].d+1][k]-(search(a[i].x)-search(a[i].x-1)));
if(i>1 && a[i].y==a[i-1].y) ans+=c[a[i-1].l+1][k]*c[a[i].r+1][k]*(search(a[i].x-1)-search(a[i-1].x));
}
printf("%d",ans&(~0u>>1));
return 0;
}