[bzoj1807] [Ioi2007]Pairs 彼此能听得见的动物对数

  这题挺神的...膜了半天claris的题解还有官方题解。。

  一维随便搞,

  二维的话就旋转坐标系,把原来的点(x,y)变成(x+y,x-y),把曼哈顿距离变成切比雪夫距离。然后排序后扫描线,树状数组维护。

  三维的话.....官方题解是旋转坐标系后直接三维树状数组?(吓哭

        Claris的题解说只要旋转后两维,预处理一波前缀和就行了....具体推一下就知道了。

  三维官方题解复杂度是nlog^3n,Claris做法是nm。。劲啊

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ll long long
 6 using namespace std;
 7 const int maxn=100233;
 8 int x[maxn];
 9 struct zs{int x,y,z;}a[maxn];
10 ll ans;
11 int i,j,k,n,m,D,id,M;
12  
13 bool cmp(zs a,zs b){return a.x<b.x;}
14 int ra;char rx;
15 inline int read(){
16     rx=getchar(),ra=0;
17     while(rx<'0'||rx>'9')rx=getchar();
18     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
19 }
20  
21 inline void run1(){
22     register int i,l=1;
23     for(i=1;i<=n;i++)x[i]=read();
24     sort(x+1,x+1+n);
25     for(i=2;i<=n;ans+=i-l,i++)while(x[i]-x[l]>D)l++;
26 }
27  
28 int t[75233<<1];
29 inline void del(int x){while(x<=M)t[x]--,x+=x&-x;}
30 inline void add(int x){while(x<=M)t[x]++,x+=x&-x;}
31 inline ll query(int x){
32     if(x<=0)return 0;
33     if(x>M)x=M;
34     ll sm=0;
35     while(x)sm+=t[x],x-=x&-x;
36     return sm;
37 }
38 inline void run2(){
39     register int i;
40     for(i=1;i<=n;i++)j=read(),k=read(),a[i].x=j+k,a[i].y=j-k+m;
41     sort(a+1,a+1+n,cmp);int top=1;
42     for(i=1;i<=n;i++){
43         while(a[top].x+D<a[i].x)del(a[top].y),top++;
44         ans+=query(a[i].y+D)-query(a[i].y-D-1),
45         add(a[i].y);
46     }
47 }
48  
49 ll mp[77][77<<1][77<<1];
50 inline ll getsm(int x,int x1,int y1,int x2,int y2){
51     if(x1<1)x1=1;if(y1<1)y1=1;
52     if(x2>M)x2=M;if(y2>M)y2=M;
53     return mp[x][x2][y2]-mp[x][x1-1][y2]-mp[x][x2][y1-1]+mp[x][x1-1][y1-1];
54 }
55 inline void run3(){
56     register int i,j,k;int x;ll tmp=0;
57     for(i=1;i<=n;i++)a[i].x=read(),j=read(),k=read(),a[i].y=j+k,a[i].z=j-k+m;
58     sort(a+1,a+1+n,cmp);
59     for(i=1;i<=n;){
60         x=a[i].x;
61         for(j=i;a[j+1].x==x;j++);
62         while(i<=j)mp[x][a[i].y][a[i].z]++,i++;
63         for(j=1;j<=M;j++)for(k=1;k<=M;k++)mp[x][j][k]+=mp[x][j-1][k]+mp[x][j][k-1]-mp[x][j-1][k-1];
64     }
65     for(i=1;i<=n;i++){
66         for(j=a[i].x+1;j<=m&&j-a[i].x<=D;j++)
67             k=D-(j-a[i].x),ans+=getsm(j,a[i].y-k,a[i].z-k,a[i].y+k,a[i].z+k);
68         tmp+=getsm(a[i].x,a[i].y-D,a[i].z-D,a[i].y+D,a[i].z+D)-1;
69     }
70     tmp>>=1;
71     ans+=tmp;
72 }
73 int main(){
74     id=read(),n=read(),D=read(),m=read();M=m<<1;
75     if(D>=m*id){printf("%lld\n",(ll)n*(n-1)/2);}
76     if(id==1)run1();
77     if(id==2)run2();
78     if(id==3)run3();
79     printf("%lld\n",ans);
80     return 0;
81 }
View Code

转载于:https://www.cnblogs.com/czllgzmzl/p/5597844.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值