zoukankan      html  css  js  c++  java
  • 【BZOJ1227】[SDOI2009]虔诚的墓主人(线段树)

    【BZOJ1227】[SDOI2009]虔诚的墓主人(线段树)

    题面

    BZOJ
    洛谷

    题解

    显然发现答案就是对于每一个空位置,考虑上下左右各有多少棵树,然后就是这四个方向上树的数量中选(K)棵出来的方案数的乘积。显然离散化之后对于答案没有任何影响,所以直接离散化。
    然而这样的点数还是(O(n^2))级别,我们把行列拆开考虑。如果我们钦定一行,从左往右看,对于一段连续的空地而言,左右的组合数的乘积是不会变化的,只有上下的乘积会改变,所以可以考虑用一个什么东西维护上下乘积,而左右乘积改变的次数之和恰好等于树的个数,这个是可以接受的。
    然而在换行的时候上下乘积是会改变的,然而发现这个的改变次数也恰好是树的个数次,所以总的改变次数就是(O(n))级别的。发现钦定行之后需要维护上下组合数乘积的结果的区间和,用线段树维护即可。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define ll long long
    #define MAX 100100
    #define lson (now<<1)
    #define rson (now<<1|1)
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,m,W,K,X[MAX],Y[MAX],ans;
    int Sx[MAX],Sy[MAX],tx,ty;
    vector<int> L[MAX];
    int R[MAX],sR[MAX];
    int C[MAX][22];
    bool cmp(int a,int b){return Y[a]<Y[b];}
    int t[MAX<<2];
    void Modify(int now,int l,int r,int p,int w)
    {
    	if(l==r){t[now]=w;return;}
    	int mid=(l+r)>>1;
    	if(p<=mid)Modify(lson,l,mid,p,w);
    	else Modify(rson,mid+1,r,p,w);
    	t[now]=t[lson]+t[rson];
    }
    int Query(int now,int l,int r,int L,int R)
    {
    	if(L>R)return 0;if(L<=l&&r<=R)return t[now];
    	int mid=(l+r)>>1,ret=0;
    	if(L<=mid)ret+=Query(lson,l,mid,L,R);
    	if(R>mid)ret+=Query(rson,mid+1,r,L,R);
    	return ret;
    }
    int main()
    {
    	n=read();m=read();W=read();
    	for(int i=1;i<=W;++i)Sx[++tx]=X[i]=read(),Sy[++ty]=Y[i]=read();
    	K=read();
    	sort(&Sx[1],&Sx[tx+1]);sort(&Sy[1],&Sy[ty+1]);
    	tx=unique(&Sx[1],&Sx[tx+1])-Sx-1;ty=unique(&Sy[1],&Sy[ty+1])-Sy-1;
    	for(int i=1;i<=W;++i)X[i]=lower_bound(&Sx[1],&Sx[tx+1],X[i])-Sx;
    	for(int i=1;i<=W;++i)Y[i]=lower_bound(&Sy[1],&Sy[ty+1],Y[i])-Sy;
    	for(int i=1;i<=W;++i)L[X[i]].push_back(i),R[Y[i]]+=1;
    	for(int i=1;i<=tx;++i)sort(L[i].begin(),L[i].end(),cmp);
    	for(int i=1;i<=tx;++i)L[i].push_back(W+1);Y[W+1]=ty+1;
    	for(int i=0;i<=W;++i)C[i][0]=1;
    	for(int i=1;i<=W;++i)
    		for(int j=1;j<=i&&j<=K;++j)
    			C[i][j]=C[i-1][j]+C[i-1][j-1];
    	for(int i=1;i<=tx;++i)
    	{
    		int ss=0,sum=L[i].size(),l,r;
    		for(int j=0;j<sum;++j)
    		{
    			l=j?Y[L[i][j-1]]:0;r=Y[L[i][j]];
    			ans+=ss*Query(1,1,ty,l+1,r-1);
    			if(j==sum-1)break;
    			ss=C[j+1][K]*C[sum-j-2][K];++sR[r];
    			Modify(1,1,ty,r,C[sR[r]][K]*C[R[r]-sR[r]][K]);
    		}
    	}
    	if(ans<0)ans+=2147483648ll;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    博客备份小工具3
    博客转发小工具1
    04-属性选择器
    05-伪类选择器
    03-高级选择器
    02-css的选择器
    01-css的引入方式
    函数进阶-(命名空间、作用域、函数嵌套、作用域链、函数名本质、闭包)
    函数基础-(引子、定义函数、调用函数、函数返回值、函数参数)
    Python之路【第08章】:Python函数
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9745791.html
Copyright © 2011-2022 走看看