[BZOJ1227] 虔诚的墓主人 (线段树+组合计数)

这是一道出现在数学专题里的数据结构题(波波真棒啊~)

式子很好写:

但是我们发现n,m<=1e9,所以应该在常青树上做文章

先把它们离散化这不用说

之后我们可以一列一列的扫,用线段树区间查询每两课常青树中的C(l[i],k)*C(r[i],k)值

之后*=C(u[j],k)*C(d[j],k)即可(它们的u和d都是一样的)

最后单点更新一下这棵树所在的行的C(l[i],k)*C(r[i],k)。

因为模数非素,且k<=10所以组合数要用杨辉三角打表。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<map>
#include<cmath>
using namespace std;
const int N=1e5+10;
const int mod=2147483648;
int k,tot,cnt,ans,n,m,w,U[N],D[N],L[N],R[N],C[N][15];
map<int,int>mx,my;
struct Taylor{int x,y,X,Y;}b[N];
struct Swift{int l,r,w;}a[N*4];
bool comp2(Taylor l,Taylor r)
{
        return l.Y<r.Y;
}
bool comp1(Taylor l,Taylor r)
{
        if(l.X==r.X) return l.Y<r.Y;
        return l.X<r.X;
}
void build(int k,int l,int r)
{
        a[k].l=l;
        a[k].r=r;
        if(l==r) return;
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
}
void change(int k,int x,int y)
{
        if(a[k].l==a[k].r)
        {
                a[k].w=y;
                return;
        }
        int mid=(a[k].l+a[k].r)>>1;
        if(x<=mid) change(k<<1,x,y);
        else change(k<<1|1,x,y);
        a[k].w=a[k<<1].w+a[k<<1|1].w;
}
int query(int k,int l,int r)
{
        if(a[k].l>=l&&a[k].r<=r) return a[k].w;
        int mid=(a[k].l+a[k].r)>>1,sum=0;
        if(l<=mid) sum+=query(k<<1,l,r);
        if(r>mid) sum+=query(k<<1|1,l,r);
        return sum;
}
void init()
{
        stable_sort(b+1,b+w+1,comp2);
        for(int i=1;i<=w;i++)
        {
                if(my[b[i].Y]==0) my[b[i].Y]=++cnt;
                b[i].y=my[b[i].Y];
                R[b[i].y]++;
        }
        stable_sort(b+1,b+w+1,comp1);
        for(int i=1;i<=w;i++)
        {
                if(mx[b[i].X]==0) mx[b[i].X]=++tot;
                b[i].x=mx[b[i].X];
        }
        C[0][0]=1;
        for(int i=1;i<=w;i++)
        {
                C[i][0]=1;
                for(int j=1;j<=min(k,i);j++)
                {
                        C[i][j]=C[i-1][j]+C[i-1][j-1];
                }
        }
        for(int i=1;i<=w;i++)
        {
                if(b[i].x!=b[i-1].x) continue;
                D[i]=D[i-1]+1;
        }
        for(int i=w;i>=1;i--)
        {
                if(b[i].x!=b[i+1].x) continue;
                U[i]=U[i+1]+1;
        }
        build(1,1,cnt);
}
int main()
{
        //freopen("1.in","r",stdin);
        scanf("%d%d%d",&n,&m,&w);
        for(int i=1;i<=w;i++)
        {
                scanf("%d%d",&b[i].X,&b[i].Y);
        }
        scanf("%d",&k);
        init();
        for(int i=1;i<=w;i++)
        {
                R[b[i].y]--;
                L[b[i].y]++;
                change(1,b[i].y,C[L[b[i].y]][k]*C[R[b[i].y]][k]);
                if(b[i].x!=b[i-1].x||b[i].y==b[i-1].y+1) continue;
                ans+=query(1,b[i-1].y+1,b[i].y-1)*C[U[i]+1][k]*C[D[i]][k];
        }
        printf("%d",ans&(mod-1));
        return 0;
}
View Code

 

posted @ 2019-07-05 14:34  ATHOSD  阅读(86)  评论(0编辑  收藏  举报