[bzoj1227] [SDOI2009]虔诚的墓主人

  终于填上了这个万年巨坑....从初二的时候就听说过这题...然后一直不敢写QAQ

  现在感觉也不是很烦(然而我还是写麻烦了

  离散化一波,预处理出组合数什么的。。

  要维护对于当前行,每列上方和下方节点凑出合法方案的个数。

  然后对于当前行上两棵相邻的常青树,求一下左边、右边合法方案数,乘上中间空的列的合法方案总数就好了。

  单点修改,区间查询。。我竟然跑去写线段树...懒得改了。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ui unsigned int
 6 using namespace std;
 7 const int maxn=100233,mxnode=maxn<<1;
 8 struct zs{int v,id;}X[maxn],Y[maxn];
 9 struct poi{int x,y;}a[maxn];
10 int lc[mxnode],rc[mxnode],num1[mxnode],num2[mxnode],tot;
11 int mp[maxn],st[maxn],top;
12 ui sm[mxnode],ans,SM,c[maxn][11];
13 int i,j,k,n,m,kk,L,R,P;
14
15
16 int ra,fh;char rx;
17 inline int read(){
18     rx=getchar(),ra=0,fh=1;
19     while((rx<‘0‘||rx>‘9‘)&&rx!=‘-‘)rx=getchar();
20     if(rx==‘-‘)fh=-1,rx=getchar();
21     while(rx>=‘0‘&&rx<=‘9‘)ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
22 }
23 void build(int a,int b){
24     int x=++tot;
25     if(a==b){num2[x]=mp[a];return;}
26     int mid=a+b>>1;
27     lc[x]=tot+1,build(a,mid),rc[x]=tot+1,build(mid+1,b);
28 }
29 void change(int x,int a,int b){
30     if(a==b){
31         num1[x]++,num2[x]--,sm[x]=c[num1[x]][kk]*c[num2[x]][kk];
32         return;
33     }
34     int mid=a+b>>1;
35     if(P<=mid)change(lc[x],a,mid);else change(rc[x],mid+1,b);
36     sm[x]=sm[lc[x]]+sm[rc[x]];
37 }
38 void query(int x,int a,int b){
39     if(L<=a&&R>=b){
40         SM+=sm[x];return;
41     }
42     int mid=a+b>>1;
43     if(L<=mid)query(lc[x],a,mid);
44     if(R>mid)query(rc[x],mid+1,b);
45 }
46
47
48 bool cmp(zs a,zs b){return a.v<b.v;}
49 bool cmpa(poi a,poi b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
50 int main(){
51     n=read(),m=read();
52     n=read();
53     for(i=1;i<=n;i++)X[i].v=read(),Y[i].v=read(),X[i].id=Y[i].id=i;
54     kk=read();
55     for(i=0;i<=n;i++)c[i][0]=1;
56     for(i=1;i<=n;i++)for(j=1;j<=kk;j++)c[i][j]=c[i-1][j]+c[i-1][j-1];
57 //  for(i=1;i<=n;i++)printf("C(%d %d)  %u\n",i,kk,c[i][kk]);return 233;
58
59     sort(X+1,X+1+n,cmp),sort(Y+1,Y+1+n,cmp);int cntx=0,cnty=0;
60     for(i=1;i<=n;a[X[i].id].x=cntx,i++)
61         if(X[i].v!=X[i-1].v||i==1)cntx++;
62     for(i=1;i<=n;a[Y[i].id].y=cnty,mp[cnty]++,i++)
63         if(Y[i].v!=Y[i-1].v||i==1)cnty++;
64     sort(a+1,a+1+n,cmpa);
65     build(1,cnty);
66
67     for(i=1;i<=n;){
68         int r=i-1,top=0;
69         while(r<n&&a[r+1].x==a[i].x)r++,st[++top]=P=a[r].y,change(1,1,cnty);//,printf("   %d",P);puts("");
70         if(top>=(kk<<1))
71         for(j=kk;j<=top-kk;j++)if(st[j]+1<st[j+1])
72             SM=0,L=st[j]+1,R=st[j+1]-1,query(1,1,cnty),
73             ans+=SM*c[j][kk]*c[top-j][kk];
74         i=r+1;
75     }
76     printf("%d\n",ans<<1>>1);
77 }

时间: 2024-12-22 14:04:55

[bzoj1227] [SDOI2009]虔诚的墓主人的相关文章

bzoj1227 [SDOI2009]虔诚的墓主人(组合公式+离散化+线段树)

1227: [SDOI2009]虔诚的墓主人 Time Limit: 5 Sec  Memory Limit: 259 MBSubmit: 803  Solved: 372[Submit][Status][Discuss] Description 小W 是一片新造公墓的管理人.公墓可以看成一块N×M 的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地.当地的居民都是非常虔诚的基督徒,他们愿意提前为自己找一块合适墓地.为了体现自己对主的真诚,他们希望自己的墓地拥有着较高的虔诚度

BZOJ1227 [SDOI2009]虔诚的墓主人 【树状数组】

题目 小W 是一片新造公墓的管理人.公墓可以看成一块N×M 的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地.当地的居民都是非常虔诚的基督徒,他们愿意提前为自己找一块合适墓地.为了体现自己对主的真诚,他们希望自己的墓地拥有着较高的虔诚度.一块墓地的虔诚度是指以这块墓地为中心的十字架的数目.一个十字架可以看成中间是墓地,墓地的正上.正下.正左.正右都有恰好k 棵常青树.小W 希望知道他所管理的这片公墓中所有墓地的虔诚度总和是多少 输入格式 第一行包含两个用空格分隔的正整数N

Bzoj 1227: [SDOI2009]虔诚的墓主人 树状数组,离散化,组合数学

1227: [SDOI2009]虔诚的墓主人 Time Limit: 5 Sec  Memory Limit: 259 MBSubmit: 895  Solved: 422[Submit][Status][Discuss] Description 小W 是一片新造公墓的管理人.公墓可以看成一块N×M 的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地.当地的居民都是非常虔诚的基督徒,他们愿意提前为自己找一块合适墓地.为了体现自己对主的真诚,他们希望自己的墓地拥有着较高的虔诚度

SDOI2009 虔诚的墓主人

1227: [SDOI2009]虔诚的墓主人 http://www.lydsy.com/JudgeOnline/problem.php?id=1227 Time Limit: 5 Sec  Memory Limit: 259 MB Description 小W 是一片新造公墓的管理人.公墓可以看成一块N×M 的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地.当地的居民都是非常虔诚的基督徒,他们愿意提前为自己找一块合适墓地.为了体现自己对主的真诚,他们希望自己的墓地拥有着较高

bzoj 1227: [SDOI2009]虔诚的墓主人

1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #define ll long long 5 #define P 2147483648LL 6 using namespace std; 7 int n,m,w,K,H[200001]; 8 ll c[100001][11],tr[200001],ans; 9 struct data{int x,y;}a[100005]; 10 int h[2

BZOJ 1227 [SDOI2009] 虔诚的墓主人 离线+树状数组+离散化

鸣谢:140142耐心讲解缕清了我的思路 题意:由于调这道题调的头昏脑涨,所以题意自己搜吧,懒得说. 方法:离线+树状数组+离散化 解析:首先深表本蒟蒻对出题人的敬(bi)意(shi).这道题简直丧心病狂,看完题后大脑一片空白,整个人都不好了,刚开始的思路是什么呢?暴力思想枚举每个墓碑,然后计算每个墓碑的虔诚度,然后再来统计.不过看看数据范围呢?10^9*10^9的矩阵,最多才10^5个树,光枚举就已经超时了,所以肯定不行.(不过要是考试真没思路我就那么搞了- -!) 然后也想到来枚举墓碑,不过

[luogu2154 SDOI2009] 虔诚的墓主人(树状数组+组合数)

传送门 Solution 显然每个点的权值可以由当前点上下左右的树的数量用组合数\(O(1)\)求出,但这样枚举会T 那么我们考虑一段连续区间,对于一行中两个常青树中间的部分左右树的数量一定,我们可用树状数组求区上下贡献值和,相乘就得到了当前区间的贡献. 有思路调不出来系列 Code #include <cmath> #include <cstdio> #include <cstring> #include <cstdlib> #include <io

luogu P2154 [SDOI2009]虔诚的墓主人

luogu 下面记一个点上下左右点数分别为\(u_i,d_i,l_i,r_i\) 枚举每个中间点太慢了,考虑枚举两个点之间横的一条线段,这里面的点左边点数目都相同,右边点数目都相同,然后只要查一下区间内\(\sum_{i=x_L+1}^{x_R-1} \binom{u_i}{k}\binom{d_i}{k}\)乘上\(\binom{l_L}{k}\binom{r_R}{k}\)就是这一段的贡献.写的时候按照纵坐标排序枚举点,然后每两个相邻点算区间的答案,区间的\(\binom{u_i}{k}\b

luogu_P2154 [SDOI2009]虔诚的墓主人

传送门:https://www.luogu.org/problem/P2154 先说说我犯的错误: 眼瞎没看到100%的数据范围 没有判断合法状态 树状数组写挂了(对单点修,区间查理解脑残了) 看下面这个图 在红色区域内的墓地,它的上下的c(down,k)*c(up,k)是不变的,所以我们可以利用这个性质. 那我们怎么得到它的左右两边的组合数积呢? 我们发现左右的组合数对答案的贡献满足加法原理的.所以我们可以维护一个单点修改区间查询的树状数组来处理这个问题. 在每次扫到一颗树的时候就对树状数组进