Codeforces 853C 树状数组

16 篇文章 0 订阅
5 篇文章 0 订阅

原题链接:http://codeforces.com/problemset/problem/853/C

对于一个矩形,可以把整个平面划分为9块区域。然后只要暴力枚举各块区域进行配对就可以得到答案。

同时用树状数组求各个区域内的格子数。

代码:

#include <bits/stdc++.h>

using namespace std;
inline void read(int &x){
    char ch;
    bool flag=false;
    for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
    for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    x=flag?-x:x;
}

inline void read(long long &x){
    char ch;
    bool flag=false;
    for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
    for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    x=flag?-x:x;
}


inline void write(int x){
    static const int maxlen=100;
    static char s[maxlen];
        if (x<0) {   putchar('-'); x=-x;}
    if(!x){ putchar('0'); return; }
    int len=0; for(;x;x/=10) s[len++]=x % 10+'0';
    for(int i=len-1;i>=0;--i) putchar(s[i]);
}

const int MAXN = 410000;
const int MAXQ = 410000;

struct Check_Point{
int x,y;
int id;
int sum;
    Check_Point(){}
    Check_Point(int x,int y,int id ):x(x),y(y),id(id){}
}point [5][ MAXQ ];

int n , m;
int a[ MAXN ];
int x[4][MAXN];
int y[4][MAXN];

int sum[ MAXN ];

int lowbit(int x){
return x&(-x);
}

void add(int x){
while (x<=n)
    {
        sum[x]++;
        x+=lowbit(x);
    }
}

int get_sum(int x){
int tmp=0;
while (x)
    {
        tmp+=sum[x];
        x-=lowbit(x);
    }
return tmp;
}

bool cmp_x( Check_Point A ,Check_Point B ){
return A.x<B.x;
}


bool cmp_id( Check_Point A ,Check_Point B ){
return A.id<B.id;
}


void doit( Check_Point point[] ){
sort( point+1, point+m+1 , cmp_x );
memset( sum , 0 , sizeof( sum ) );
int now=1;
for (int i=1;i<=m;i++)
    {
        int r=i;
        while ( ( r< m ) && ( point[ r+1 ].x == point[ i ].x ) )
            r++;
        while ( (now<=n ) && ( now< point [ i ].x ) )
            add( a[now++] );
        for (int j=i;j<=r;j++)
            point[j].sum = get_sum( point[j].y-1 );
        i=r;
    }
}

int tmp[5][5];

int main(){
    read(n); read(m);
    for (int i=1;i<=n;i++)
        read(a[i]);
    for (int i=1;i<=m;i++)
        {
            int a,b,c,d;
            read(a); read(b); read(c); read(d);
            x[1][i]=a; x[2][i]=c;
            y[1][i]=b; y[2][i]=d;
            point[1][i] = Check_Point( a , b , i );
            point[2][i] = Check_Point( a , n+1-d , i );
            point[3][i] = Check_Point( n+1-c , b , i );
            point[4][i] = Check_Point( n+1-c , n+1-d , i );
        }
    doit( point[1] );
    for (int i=1;i<=n;i++)
        a[i]=n+1-a[i];
    doit( point[2] );
    reverse( a+1 , a+n+1 );
    doit( point[4] );
    for (int i=1;i<=n;i++)
        a[i]=n+1-a[i];
    doit( point[3] );
    for (int i=1;i<=4;i++)
        sort( point[i]+1, point[i]+1+m , cmp_id );

    for (int i=1;i<=m;i++)
        {
            long long ans=0;
            tmp[1][1] = point[1][i].sum;
            tmp[3][1] = point[3][i].sum;
            tmp[1][3] = point[2][i].sum;
            tmp[3][3] = point[4][i].sum;
            tmp[1][2] = x[1][i] - tmp[1][1] - tmp[1][3]-1;
            tmp[2][1] = y[1][i] - tmp[1][1] - tmp[3][1]-1;
            tmp[2][3] = n - y[2][i] - tmp[1][3] - tmp[3][3];
            tmp[3][2] = n - x[2][i] - tmp[3][1] - tmp[3][3];
            tmp[2][2] = x[2][i] - x[1][i] +1 -tmp[2][1]-tmp[2][3];
            ans+=1ll*tmp[1][1]*(tmp[2][2]+tmp[2][3]+tmp[3][2]+tmp[3][3]);
            ans+=1ll*tmp[1][2]*(n-x[1][i]+1);
            ans+=1ll*tmp[1][3]*(tmp[2][2]+tmp[2][1]+tmp[3][2]+tmp[3][1]);
            ans+=1ll*tmp[2][1]*(tmp[2][2]+tmp[2][3]+tmp[3][2]+tmp[3][3]);
            ans+=1ll*tmp[2][2]*(tmp[2][3]+tmp[3][1]+tmp[3][2]+tmp[3][3]);
            ans+=1ll*tmp[2][3]*(tmp[3][1]+tmp[3][2]);
            ans+=1ll*tmp[2][2]*(tmp[2][2]-1)/2ll;
            /*
            for (int j=3;j>=1;j--)
            {
                for (int k=1;k<=3;k++)
                    printf("%d ",tmp[k][j]);
                puts("");
            }
            */
            printf("%I64d\n",ans);
        }
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值