zoukankan      html  css  js  c++  java
  • BZOJ1176 Mokia CDQ分治

    题目描述

    维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.

    输入格式

    第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小
    接下来每行为一下三种输入之一(不包含引号):
    "1 x y a"
    "2 x1 y1 x2 y2"
    "3"
    输入1:你需要把(x,y)(第x行第y列)的格子权值增加a
    输入2:你需要求出以左下角为(x1,y1),右上角为(x2,y2)的矩阵内所有格子的权值和,并输出
    输入3:表示输入结束

    输出格式

    对于每个输入2,输出一行,即输入2的答案

    样例

    样例输入

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

    样例输出

    3
    5

    数据范围与提示

    保证答案不会超过int范围

      之前做过一道叫做移动电话的题,后来发现这道题数据加到二维树状数组开不出来。。。话说移动电话居然是IOI2001,这简直了,当时可能没有树状数组,可能也没有线段树,可能$n^{2}$是正解。。。我们说正题,如何用CDQdalao的离线分治解决呢。。。

      首先这个题我们离线做,把所有操作打上时间戳,然后就有三维了。这样考虑一个查询,拆成4个矩形加加减减,我们就可以维护一个坐标与原点围成的矩形中点个数。而且一个修改对查询有影响,当且仅当x,y,t都小于它,标准三维偏序,CDQ套上就可以了

      

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=200020,M=2000020;
    struct node
    {
        int a,b,t,f,w;
        int op;
    }a[N],t[N];
    int b[M],n,ans[N],S,m,tt;
    int rd()
    {
        int s=0,w=1;
        char cc=getchar();
        while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
        while(cc>='0'&&cc<='9') s=(s<<1)+(s<<3)+cc-'0',cc=getchar();
        return s*w;
    }
    void add(int x,int w)
    {
        for(int i=x;i<=m;i+=(i&-i))
            b[i]+=w;
    }
    int sum(int x)
    {
        int ans=0;
        for(int i=x;i;i-=(i&-i))
            ans+=b[i];
        return ans;
    }
    bool cmp(node a,node b)
    {
        if(a.t!=b.t)return a.t<b.t;
        if(a.a!=b.a)return a.a<b.a;
        return a.b<b.b;
    }
    void CDQ(int l,int r)
    {
        if(l==r) return;
        int mid=(l+r)>>1;
        CDQ(l,mid);CDQ(mid+1,r);
        int p=l,q=mid+1,cnt=l-1;
        while(p<=mid&&q<=r)
        {
            //cout<<p<<" "<<q<<endl;
            if(a[p].a<=a[q].a)
            {
                if(a[p].op==0)add(a[p].b,a[p].w);
                t[++cnt]=a[p++];
            }
            else
            {
                if(a[q].op>0)a[q].f+=sum(a[q].b);
                t[++cnt]=a[q++];
            }
        }
        while(p<=mid)
        {
            if(a[p].op==0)add(a[p].b,a[p].w);
            t[++cnt]=a[p++];
        }
        
        while(q<=r)
        {
            if(a[q].op>0) a[q].f+=sum(a[q].b);
            t[++cnt]=a[q++];
        }
        for(int i=l;i<=mid;i++) if(a[i].op==0)add(a[i].b,-a[i].w);
        for(int i=l;i<=r;i++) a[i]=t[i];
    }
    bool cmp2(node a,node b)
    {
        if(a.t==b.t) return a.op<b.op;
        return a.t<b.t;
    }
    void asd(int x,int y,int t,int op,int w)
    {
        //cout<<tt<<" "<<x<<" "<<y<<endl;
        a[++tt].a=x,a[tt].b=y;a[tt].t=t;
        a[tt].op=op;a[tt].w=w;
    }
    int main()
    {
        S=rd(),m=rd()+1;
        int cnt=0,xa,xb,ya,yb,x,w,y;
        for(int i=1;;i++)
        {
            int op=rd();
            if(op==3) break;
            if(op==2)
            {
                cnt++;
                xa=rd()+1,ya=rd()+1;
                xb=rd()+1,yb=rd()+1;
                asd(xb,yb,i,1,0);
                asd(xa-1,yb,i,2,0);
                asd(xb,ya-1,i,3,0);
                asd(xa-1,ya-1,i,4,0);
            }
            if(op==1)
            {
                x=rd()+1,y=rd()+1,w=rd();
                asd(x,y,i,0,w);
            }
        }//(xa,yb)-(xa,ya-1)-(xb-1,yb)+(xb-1,ya-1)
        sort(a+1,a+tt+1,cmp);
        CDQ(1,tt);
        for(int i=1;i<=tt;i++)
        {
            //cout<<i<<" "<<a[i].t<<endl;
            switch(a[i].op)
            {
                case 1:
                {
                    ans[a[i].t]+=a[i].f+(a[i].a*a[i].b*S);
                    break;
                }
                case 2:
                {
                    ans[a[i].t]-=a[i].f+(a[i].a*a[i].b*S);
                    break;
                }
                case 3:
                {
                    ans[a[i].t]-=a[i].f+(a[i].a*a[i].b*S);
                    break;
                }
                case 4:
                {
                    ans[a[i].t]+=a[i].f+(a[i].a*a[i].b*S);
                    break;
                }
            }
            
        }
        sort(a+1,a+tt+1,cmp2);
        for(int i=1;i<=tt;i++)
        {
            if(a[i].op==4) printf("%d
    ",ans[a[i].t]);
        }
    }
    /*
    g++ 1.cpp -o 1
    ./1
    0 4
    1 2 3 3
    2 1 1 3 3
    1 2 2 2
    2 2 2 3 4
    3
    */
    /*
    g++ -g 1.cpp -o 1
    gdb -q 1
    b 42
    r
    0 4
    1 2 3 3
    2 1 1 3 3
    1 2 2 2
    2 2 2 3 4
    3
    */
    View Code
    Zeit und Raum trennen dich und mich.时空将你我分开。
  • 相关阅读:
    Windows核心编程 第八章 用户方式中线程的同步(下)
    Windows核心编程 第八章 用户方式中线程的同步(下)
    Windows核心编程 第八章 用户方式中线程的同步(上)
    Windows核心编程 第八章 用户方式中线程的同步(上)
    Windows PE 第四章 导入表
    Windows PE 第四章 导入表
    PAT 1005 继续(3n+1)猜想
    PAT 甲级 1002 A+B for Polynomials
    HDU 1798 Tell me the area
    HDU 1159 Common Subsequence
  • 原文地址:https://www.cnblogs.com/starsing/p/11253701.html
Copyright © 2011-2022 走看看