zoukankan      html  css  js  c++  java
  • 【BZOJ1176】[Balkan2007]Mokia/【BZOJ2683】简单题 cdq分治

    【BZOJ1176】[Balkan2007]Mokia

    Description

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

    Input

    第一行两个整数,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:表示输入结束

    Output

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

    Sample Input

    0 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

    保证答案不会超过int范围

    【BZOJ2683】简单题

    题意:和上面一样

    题解:依旧是分治思路

    我们将询问差分,拆成四个点分别求前缀和,然后将询问和修改一起按横坐标排序;

    然后在跑cdq分治的时候,我们一边递归一边按照修改的时间进行归并排序。根据cdq分治的思想,我们在执行区间[l,r]时已经处理完[l,mid]和[mid+1,r]了,那么我们只需要处理[l,mid]中的修改对[mid+1,r]中的询问造成的影响。于是我们在跑归并排序的时候,将[l,mid]中的修改按照纵坐标插入树状数组,然后将[mid+1,r]中的询问按照纵坐标在树状数组上查找,再更新一下答案就好了

    这代码我已经不怎么压行了,是不是可读性高了好多。。。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,num,m;
    const int maxn=200010;
    struct node
    {
    	int x,y,org,v,k;
    }s[maxn];
    int p[maxn],q[maxn],tr[maxn*10],ans[maxn];
    //p是归并排序的顺序,q是p的复制
    bool cmp(node a,node b)
    {
    	if(a.x==b.x&&a.org==b.org)	return a.y<b.y;
    	if(a.x==b.x)	return a.org<b.org;
    	return a.x<b.x;
    }
    void updata(int a,int val)
    {
    	for(int i=a;i<=n;i+=i&-i)	tr[i]+=val;
    }
    int query(int a)
    {
    	int i,ret=0;
    	for(i=a;i;i-=i&-i)	ret+=tr[i];
    	return ret;
    }
    void dfs(int l,int r)
    {
    	if(l==r)
    	{
    		p[l]=l;
    		return ;
    	}
    	int i,mid=l+r>>1,h1=l,h2=mid+1;
    	dfs(l,mid),dfs(mid+1,r);
    	for(i=l;i<=r;i++)
    	{
    		if(h2<=r&&(h1>mid||s[p[h1]].org>=s[p[h2]].org))
    		{
    			if(!s[p[h2]].k)	ans[s[p[h2]].org]+=s[p[h2]].v*query(s[p[h2]].y);
    			q[i]=p[h2++];
    		}
    		else
    		{
    			if(s[p[h1]].k)	updata(s[p[h1]].y,s[p[h1]].v);
    			q[i]=p[h1++];
    		}
    	}
    	for(i=l;i<=mid;i++)	if(s[p[i]].k)	updata(s[p[i]].y,-s[p[i]].v);
    	for(i=l;i<=r;i++)	p[i]=q[i];
    }
    int main()
    {
    	int i,a,b,c,d,e;
    	scanf("%d%d",&a,&n);
    	for(i=1;e!=3;i++)
    	{
    		scanf("%d",&e);
    		if(e==1)
    		{
    			scanf("%d%d%d",&a,&b,&c);
    			s[++num].x=a,s[num].y=b,s[num].org=m,s[num].k=1,s[num].v=c;
    		}
    		if(e==2)
    		{
    			scanf("%d%d%d%d",&a,&b,&c,&d),a--,b--;
    			s[num+1].org=s[num+2].org=s[num+3].org=s[num+4].org=++m;
    			s[num+1].k=s[num+2].k=s[num+3].k=s[num+4].k=0;
    			s[++num].x=a,s[num].y=b,s[num].v=1;
    			s[++num].x=a,s[num].y=d,s[num].v=-1;
    			s[++num].x=c,s[num].y=b,s[num].v=-1;
    			s[++num].x=c,s[num].y=d,s[num].v=1;
    		}
    	}
    	sort(s+1,s+num+1,cmp);
    	dfs(1,num);
    	for(i=1;i<=m;i++)	printf("%d
    ",ans[i]);
    	return 0;
    }
  • 相关阅读:
    java 面向对象(六):类结构 方法(三) java的值传递机制
    java 面向对象(五):类结构 方法(二) 关键字:return;方法的重载;可变个数形参的方法
    java 面向对象(四):类结构 方法(一)
    java 面向对象(三):类结构 属性
    java 面向对象(二):JVM内存结构
    java 面向对象(一):类与对象
    java 基本语法(十三) 数组(六)数组的常见异常
    java 基本语法(十二) 数组(五)Arrays工具类的使用
    java 基本语法(十一) 数组(四)数组的常见算法
    java 基本语法(十) 数组(三) 二维数组
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6599277.html
Copyright © 2011-2022 走看看