【Luogu】P2154虔诚的墓主人(树状数组)

  题目链接

  这题就是考虑我们有这样一个情况

  然后我们试图很方便地求出第三行第二个和第三个常青树之间所有点上下常青树的组合。

  考虑使用树状数组,一开始把数组平放在最底下,然后往上推。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<cstring>
#define maxn 200020
#define maxd 12
#define mod 2147483648
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

struct Tree{
    long long x,y;
    bool operator <(const Tree a)const{
        if(x!=a.x)    return x<a.x;
        return y<a.y;
    }
}q[maxn];

long long s[maxn*2],cnt;
long long c[maxn][maxd];

long long tree[maxn*2];
inline long long low(long long x){    return x&(-x);    }

inline void add(long long pos,long long lim,long long num){
    while(pos<=lim){
        tree[pos]+=num;
        tree[pos]%=mod;
        pos+=low(pos);
    }
    return;
}

inline long long query(long long pos){
    long long ans=0;
    while(pos){
        ans+=tree[pos];
        ans%=mod;
        pos-=low(pos);
    }
    return ans;
}


long long up[maxn],down[maxn];
long long lef[maxn],rig[maxn];

int main(){
    long long m=read()+1,n=read()+1;
    long long e=read();
    for(long long i=1;i<=e;++i){
        q[i]=(Tree){read(),read()};
        swap(q[i].x,q[i].y);
        s[++cnt]=q[i].x;    s[++cnt]=q[i].y;
    }
    sort(s+1,s+cnt+1);
    long long size=unique(s+1,s+cnt+1)-s-1;
    for(long long i=1;i<=e;++i){
        q[i].x=lower_bound(s+1,s+size+1,q[i].x)-s;
        q[i].y=lower_bound(s+1,s+size+1,q[i].y)-s;
    }
    sort(q+1,q+e+1);
    for(long long i=1;i<=e;++i){
        up[q[i].y]++;
        rig[q[i].x]++;
    }
    long long d=read();
    for(long long i=0;i<=e;++i)    c[i][0]=1;
    for(long long i=1;i<=e;++i)
        for(long long j=1;j<=d;++j)    c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    long long ans=0;
    for(long long i=1;i<=e;++i){
        if(q[i].x==q[i-1].x&&i!=1){
            //printf("i=%d\nxi=%d yi=%d\n%d %d %d %d\n",i,q[i].x,q[i].y,lef[q[i].x],rig[q[i].x],query(q[i].y),query(q[i].y-q[i-1].y));
            ans+=c[lef[q[i].x]][d]*c[rig[q[i].x]][d]*(query(q[i].y-1)-query(q[i-1].y))%mod;
        }
        
        up[q[i].y]--;    down[q[i].y]++;
        lef[q[i].x]++;    rig[q[i].x]--;
        add(q[i].y,size,c[up[q[i].y]][d]*c[down[q[i].y]][d]-query(q[i].y)+query(q[i].y-1));
    }
    printf("%lld\n",(ans%mod+mod)%mod);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cellular-automaton/p/8952120.html