BZOJ 2727: [HNOI2012]双十字

如果你有一道题一上午都没调出来

那么一定是你取模取错了QAQ

下意识地对(1e9)+7取了模,现在才发现是(1e9)+9

这个首先推一下公式,然后开三个树状数组维护一下就好了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N=1200000+5;
typedef long long ll;
const int p=(1e9)+9;
int mp[N],c[N],down[N];
int n,m;
int id(int x,int y){
	return (x-1)*m+y;
}
struct BIT{
	ll d[N];
	int vis[N],T;
	void clear(){T++;}
	int lowbit(int x){return x&-x;}
	void add(int x,ll v){
		for(;x<=m;x+=lowbit(x)){
			if(vis[x]!=T)vis[x]=T,d[x]=0;
			d[x]=(d[x]+v)%p;
		}
	}
	ll sum(int x){
		ll ans=0;
		for(;x;x-=lowbit(x))if(vis[x]==T)ans=(ans+d[x])%p;
		return ans;
	}
}t1,t2,t3;
int main(){
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	scanf("%d%d",&n,&m);
	int k;scanf("%d",&k);
	for(int i=1;i<=k;i++){
		int x,y;scanf("%d%d",&x,&y);
		mp[id(x,y)]=1;
	}
	for(int i=1;i<=n;i++){
		int mark=0;
		for(int j=1;j<=m;j++){
			int t=id(i,j);
			if(mp[t])mark=j;
			else c[t]=j-mark-1;
		}
		mark=m+1;
		for(int j=m;j>=1;j--){
			int t=id(i,j);
			if(mp[t])mark=j;
			else c[t]=min(c[t],mark-j-1);
		}
	}
	for(int j=1;j<=m;j++){
		int mark=n+1;
		for(int i=n;i>=1;i--){
			int t=id(i,j);
			if(mp[t])mark=i;
			else down[t]=mark-i-1;
		}
	}
	ll ans=0;
	for(int j=1;j<=m;j++){
		t1.clear();t2.clear();t3.clear();
		int top=0;
		for(int i=1;i<=n;i++){
			int t=id(i,j);
			if(mp[t]){top=i;t1.clear();t2.clear();t3.clear();continue;}
			ans+=t1.sum(c[t])*down[t]%p;
			ans+=t2.sum(c[t])*c[t]*down[t]%p;
			ans+=(t3.sum(m)-t3.sum(c[t]))*(c[t]-1)*c[t]/2*down[t]%p;
			ans%=p;t=id(i-1,j);
			if (i==1) continue;  
            if (c[t]){  
                t1.add(c[t],-1ll*c[t]*(c[t]+1)/2*(i-1-top-1));  
                t2.add(c[t],c[t]*(i-1-top-1));  
                t3.add(c[t],i-1-top-1);  
            }
       }
	}
	printf("%lld\n",ans);
	return 0;
}



你可能感兴趣的:(BZOJ 2727: [HNOI2012]双十字)