bzoj2683&&1176 CDQ分治

2683: 简单题
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。
ps:1176只是多了个初始值~

分析:

看到数据范围,就知道二维树状数组不行。
于是想如何就二维转化为一维。便想到了CDQ分治~~

考虑把 (x1,y1)(x1,y1) (x2,y2)(x2,y2) 的矩阵拆成
(x11,y11) , (x11,y2) , (x2,y11) , (x2,y2) 然后容斥原理搞搞就行了。
矩阵拆开后和操作1一起按插入时间排序。
然后二分时间,因为分治的左区间对右区间有贡献于是将右区间所有操作1搞到树状数组中,左区间的询问操作进行统计。
再用O(r-l+1)的时间将数组按时间(与mid比较)分成左右两部分
继续向下递归。。。

#include
#include
#include

using namespace std;
const int N=800100;
int n,m,tot,ans[N],w,x1,yy1,x2,y2,k,c[N],cnt;
struct node{int x,y,id,op,z,c;}g[N],t[N];

int cmp(node a,node b)
{
    if (a.x!=b.x) return a.xx;
    if (a.y!=b.y) return a.yy;
    return a.idint x,int val)
{
    while (x<=n)
    {
        c[x]+=val;
        x+=x&-x;
    }
}

int query(int x)
{
    int res=0;
    while (x)
    {
        res+=c[x];
        x-=x&-x;
    }
    return res;
}

void cdq(int l,int r)
{
    if (l==r) return;
    int mid=(l+r)/2;
    for (int i=l;i<=r;i++)
    {
        if (g[i].op==1 && g[i].id<=mid) ins(g[i].y,g[i].z);
        if (g[i].op==2 && g[i].id>mid) ans[g[i].c]+=g[i].z*query(g[i].y);
    }
    for (int i=l;i<=r;i++)
    if (g[i].op==1 && g[i].id<=mid)
        ins(g[i].y,-g[i].z);
    int l1=l,l2=mid+1;
    for (int i=l;i<=r;i++)
    if (g[i].id<=mid)
        t[l1++]=g[i]; else
        t[l2++]=g[i];
    for (int i=l;i<=r;i++)
        g[i]=t[i];
    cdq(l,mid);cdq(mid+1,r);
}

int main()
{
    freopen("a.in","r",stdin);
    scanf("%d%d",&w,&n);
    while (1)
    {
        scanf("%d",&k);
        if (k==3) break;
        int t;
        if (k==1)
        {
            scanf("%d%d%d",&x1,&yy1,&t);
            g[++tot].x=x1;
            g[tot].y=yy1;
            g[tot].z=t;
            g[tot].op=1;
            g[tot].id=tot;
        } else
        {
            scanf("%d%d%d%d",&x1,&yy1,&x2,&y2);
            ans[++cnt]=(x2-x1+1)*(y2-yy1+1)*w;
            g[++tot].x=x1-1;g[tot].y=yy1-1;g[tot].op=2;g[tot].z=1;g[tot].c=cnt;g[tot].id=tot;
            g[++tot].x=x2;g[tot].y=y2;g[tot].op=2;g[tot].z=1;g[tot].c=cnt;g[tot].id=tot;
            g[++tot].x=x1-1;g[tot].y=y2;g[tot].op=2;g[tot].z=-1;g[tot].c=cnt;g[tot].id=tot;
            g[++tot].x=x2;g[tot].y=yy1-1;g[tot].op=2;g[tot].z=-1;g[tot].c=cnt;g[tot].id=tot;
        }
    }
    sort(g+1,g+tot+1,cmp);
    cdq(1,tot);
    for (int i=1;i<=cnt;i++)
        printf("%d\n",ans[i]);
}

你可能感兴趣的:(bzoj,CDQ分治)