BZOJ2683 简单题 题解&代码

26 篇文章 0 订阅
1 篇文章 0 订阅

题意:
给出n*n的棋盘,初始值为0,维护两种操作:
1 x y a 给(x,y)处加a
2 x1 y1 x2 y2 查询(x1,y1)(x2,y2)的矩形内部的和
对每次求和都需要输出答案

思路:
其实我是直接看题解是cdq分治的【捂脸】不敢随意装逼,只是写了一次cdq分治熟悉了一下
插入和查询都是单点操作(查询操作可以修改为4个单点的二维前缀和)
不知所云…有点尴尬,我思考一下再说orz

/**************************************************************
    Problem: 2683
    User: Rainbow6174
    Language: C++
    Result: Accepted
    Time:8064 ms
    Memory:27060 kb
****************************************************************/

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxc = 200005;
int n,c,tot,cnt,x1,y1,x2,y2,a[maxc*4],p[maxc*4],x[maxc*4],y[maxc*4],z[maxc*4],op[maxc*4],ans[maxc],id[maxc*4],ls[maxc*4];
bool cmp(int idx,int idy)
{
    if(x[idx]==x[idy])
        if(y[idx]==y[idy])return z[idx]<z[idy];
        else return y[idx]<y[idy];
    return x[idx]<x[idy];
}
int lowbit(int x)
{
    return x&(-x);
}
void insert(int x,int l)
{
    for(int i = x; i < maxc*4; i+=lowbit(i))
        a[i]+=l;
}
int getsum(int x)
{
    int ret = 0;
    for(int i = x; i > 0; i-=lowbit(i))
        ret+=a[i];
    return ret;
}
void cdq(int l,int r)
{
    if(l==r)return;
    //cout<<l<<' '<<r<<endl;
    int mid=(l+r)/2;
    for(int i = l; i <= r; i++)
    if(z[p[i]]==1){
        if(p[i]<=mid) insert(y[p[i]],op[p[i]]);
    }
    else if(p[i]>mid){
        ans[id[p[i]]] += op[p[i]]*getsum(y[p[i]]);
    }
    for(int i = l; i <= r; i++)
        if(z[p[i]]==1 && p[i]<=mid) insert(y[p[i]],-op[p[i]]);
    int l1=l,l2=mid+1;
    for(int i = l; i <= r; i++)
        if(p[i]<=mid) ls[l1++] = p[i];
        else ls[l2++] = p[i];
    for(int i = l; i <= r; i++) p[i] = ls[i];
    cdq(l,mid);
    cdq(mid+1,r);
}
int main(void)
{
    scanf("%d",&n);
    while(scanf("%d",&c) && c!=3)
    {
        p[++tot]=tot;z[tot]=c;
        if(c==1)scanf("%d%d%d",&x[tot],&y[tot],&op[tot]);
        else
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            x[tot]=x1-1;y[tot]=y1-1;op[tot]=1;id[tot]=++cnt;
            p[++tot]=tot;z[tot]=c;
            x[tot]=x1-1;y[tot]=y2;op[tot]=-1;id[tot]=cnt;
            p[++tot]=tot;z[tot]=c;
            x[tot]=x2;y[tot]=y1-1;op[tot]=-1;id[tot]=cnt;
            p[++tot]=tot;z[tot]=c;
            x[tot]=x2;y[tot]=y2;op[tot]=1;id[tot]=cnt;
        }
    }
    sort(p+1,p+1+tot,cmp);
    //for(int i = 1; i <= tot; i++)
        //cout<<p[i]<<' '<<id[p[i]]<<' '<<z[p[i]]<<' '<<op[p[i]]<<' '<<x[p[i]]<<' '<<y[p[i]]<<' '<<getsum(y[i])<<endl;
    cdq(1,tot);
    for(int i = 1; i <= cnt; i++)printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值