zoukankan      html  css  js  c++  java
  • BZOJ#2683. 简单题

    2683: 简单题

    Time Limit: 50 Sec  Memory Limit: 128 MB
    Submit: 2091  Solved: 847

    Description

    你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:

    命令

    参数限制

    内容

    1 x y A

    1<=x,y<=N,A是正整数

    将格子x,y里的数字加上A

    2 x1 y1 x2 y2

    1<=x1<= x2<=N

    1<=y1<= y2<=N

    输出x1 y1 x2 y2这个矩形内的数字和

    3

    终止程序

    Input

    输入文件第一行一个正整数N。
    接下来每行一个操作。

    Output

    对于每个2操作,输出一个对应的答案。

    Sample Input

    4
    1 2 3 3
    2 1 1 3 3
    1 2 2 2
    2 2 2 3 4
    3

    Sample Output

    3
    5

    HINT

    1<=N<=500000,操作数不超过200000个,内存限制20M。

    对于100%的数据,操作1中的A不超过2000。
     

    题目大意:

    给了一个矩形,有查询去其中某个矩形权值之和和修改某个位置的值的操作。


    分析:

    CDQ裸题

    我们可以很方便求出一个前缀面积,就是(0,0)(x,y)的面积,我们只需要按时间排序,在里面再按x排序,y加入树状数组
    找到time>time[i],x>=x[i],y>=y[i]即可
    那么我们怎么求(x,y)(c,d)的矩形呢?
    我们可以把它拆成4个矩形(0,0)(x-1,y-1),(0,0)(x-1,d),(0,0)(c,d),(0,0)(c,y-1)
    合并一下就可以了


    附上代码:
    //CDQ把每个查询矩形划分为4部分 每部分可以单独求出
    //求出的方法是找到x1<x2,y1<y2,时间在他出现之前
    //合并答案 
    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e5+12;
    const int M=8e5+12;
    struct date
    {
        int type,x,y,v,id;
    }d[M];
    int n,m,cnt,c[N],pos[M],ans[M];
    
    int cmp(date a,date b)
    {
        return a.x<b.x;
    }
    
    inline int lowbit(int x) {return x&(-x);}
    void add(int a,int b)
    {
        while(a<=n) 
        {
            c[a]+=b;
            a+=lowbit(a);
        }
    }
    int sum(int a)
    {
        int s=0;
        while(a)
        {
            s+=c[a];
            a-=lowbit(a);
        }
        return s;
    }
    
    void CDQ(int l,int r)
    {
        if(l==r) return ;
        int mid=(l+r)>>1,temp=0;
        CDQ(l,mid);CDQ(mid+1,r);
        sort(d+l,d+mid+1,cmp);sort(d+mid+1,d+r+1,cmp);
        int i=l,j=mid+1;
        while(j<=r)
        {
            while(d[i].type==2&&i<=mid) i++;
            while(d[j].type==1&&j<=r) j++;
            if(i<=mid&&d[i].x<=d[j].x) add(d[i].y,d[i].v),i++,temp=i-1;
            else if(j<=r) ans[d[j].id]+=sum(d[j].y),j++;
        }
        for(int i=l;i<=temp;i++) if(d[i].type==1) add(d[i].y,-d[i].v);
    }
    
    int main()
    {
        freopen("a.in","r",stdin);
        int type,x1,x2,y1,y2;
        scanf("%d",&n);
        while(1)
        {
            scanf("%d",&type);
            if(type==3) break;
            if(type==1)
            {
                d[++m].type=type;d[m].id=m;
                scanf("%d%d%d",&d[m].x,&d[m].y,&d[m].v);
            }
            else 
            {
                scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                pos[++cnt]=m;
                d[++m].type=type;d[m].x=x1-1;d[m].y=y1-1;d[m].id=m;
                d[++m].type=type;d[m].x=x2;d[m].y=y2;d[m].id=m;
                d[++m].type=type;d[m].x=x1-1;d[m].y=y2;d[m].id=m;
                d[++m].type=type;d[m].x=x2;d[m].y=y1-1;d[m].id=m;
            }
        }
        CDQ(1,m);
        for(int i=1;i<=cnt;i++) printf("%d
    ",ans[pos[i]+1]+ans[pos[i]+2]-ans[pos[i]+3]-ans[pos[i]+4]);
        return 0;
    }
    View Code

  • 相关阅读:
    c# 操作数据库
    dataview findrows
    C++:gethostname,gethostbyname获取IP地址和计算机名
    MQTT
    STM32操作外部SRAM
    JAVA中最常用的快捷键总结
    Zstack中End Device设备失去父节点时的重新入网处理方法(转)
    VC++ 重叠窗口
    (转载)PLC内部电路常见的几种形式
    VS2005 DoModal函数
  • 原文地址:https://www.cnblogs.com/Heey/p/9006213.html
Copyright © 2011-2022 走看看