ZOJ 3018 Population(二维线段树?矩形树?)

地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3018

题意:在平面内最多又32768个点,现在有两种操作,1:在一些点上加上一个数n,2:询问一个矩形区域内的点的数的和

分析:这题一看像线段树,想离线搞,发现不好处理,也许可以,不过我是做不来了,后来自己YY了下二维的线段树,从来没写过= =,一开始发现空间会爆,再一想,其实很多节点是没必要增加的,然后就可以做了,大体思路如下:

每个节点保存一个矩形,还有这个矩形区域内的和,这个节点可以分为四个子节点,现在对于插入操作,直接不停的将矩形范围缩小,直到成为一个点,这样每个点最多带来log(n)个节点(n为离散化后x或y的数量),也就是总的节点个数为32768*logn,这样是完全可以的,而查找的话,跟线段树差不多,每次判断当前区域是否覆盖整个节点,是的话就返回这块区域的和,否则就递归与之有覆盖的子矩形。。。好吧,好久没写,表达能力又变差了,具体看代码,感觉练了一阵子的各种树,再写这样的题还是得心应手的^_^

代码:

/** head files*/
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cassert>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <list>
#include <stdexcept>
#include <functional>
#include <utility>
#include <ctime>
using namespace std;

/** some operate*/
#define REP(i,n) for(int i=0;i<(n);++i)
#define FOR(i,l,h) for(int i=(l);i<=(h);++i)
#define DWN(i,h,l) for(int i=(h);i>=(l);--i)
#define foreach(e,x) for(__typeof(x.begin()) e=x.begin();e!=x.end();++e)
#define CLR(arr) memset(arr,0,sizeof(arr))
#define MAX3(a,b,c) max(a,max(b,c))
#define MAX4(a,b,c,d) max(max(a,b),max(c,d))
#define MIN3(a,b,c) min(a,min(b,c))
#define MIN4(a,b,c,d) min(min(a,b),min(c,d))

/** some const*/
#define N 800100
#define PI acos(-1.0)
#define oo 1000000000
#define loo 1000000000000000000LL
#define eps 1e-8
/** some alias*/
typedef long long LL;

int dx[]={0,0,-1,1};
int dy[]={-1,1,0,0};
/** Global variables*/

/** some template names, just push ctrl+j to get it in*/
//getint 读入优化
//manacher 求最长回文子串
//pqueue 优先队列
//combk n元素序列的第m小的组合和
//pmatrix n个点的最大子矩阵
//suffixarray 后缀数组
//sbtree 平衡树
struct retange
{
    int x1,y1,x2,y2;
    retange(){}
    retange(int x1, int y1, int x2, int y2):x1(x1),y1(y1),x2(x2),y2(y2){}
    bool cover(const retange &a)const
    {
        if(x1>a.x1||x2<a.x2||y1>a.y1||y2<a.y2)return 0;
        return 1;
    }
    bool interset(const retange &a)const
    {
        if(x1>a.x2||y1>a.y2||a.x1>x2||a.y1>y2)return 0;
        return 1;
    }
    bool ok()
    {
        return x1>=x2&&y1>=y2;
    }
    int mx()
    {
        return (x1+x2)>>1;
    }
    int my()
    {
        return (y1+y2)>>1;
    }
    void rd(char *s)
    {
        sscanf(s,"%d%d%d%d",&x1,&x2,&y1,&y2);
    }
};
struct Node
{
    retange r;
    Node *son[4];
    LL sum;
}TNode,*nil=&TNode;
Node mem[N],*C=mem;
Node* Create(retange r)
{
    C->r=r;
    C->sum=0;
    REP(i,4)C->son[i]=nil;
    return C++;
}
void Update(int x, int y, int n, Node *now)
{
    now->sum+=n;
    while(1)
    {
        int mx=now->r.mx();
        int my=now->r.my();
        if(x<=mx)
        {
            if(y<=my)
            {
                if(now->son[0]==nil)
                    now->son[0]=Create(retange(now->r.x1,now->r.y1,mx,my));
                now=now->son[0];
            }
            else
            {
                if(now->son[1]==nil)
                    now->son[1]=Create(retange(now->r.x1,my+1,mx,now->r.y2));
                now=now->son[1];
            }
        }
        else
        {
            if(y<=my)
            {
                if(now->son[2]==nil)
                    now->son[2]=Create(retange(mx+1,now->r.y1,now->r.x2,my));
                now=now->son[2];
            }
            else
            {
                if(now->son[3]==nil)
                    now->son[3]=Create(retange(mx+1,my+1,now->r.x2,now->r.y2));
                now=now->son[3];
            }
        }
        now->sum+=n;
        if(now->r.ok())break;
    }
}
LL Query(retange r, Node *now)
{
    if(r.cover(now->r))return now->sum;
    LL ret=0;
    REP(i,4)
        if(now->son[i]!=nil&&now->son[i]->r.interset(r))
            ret+=Query(r,now->son[i]);
    return ret;
}
char s[333];
int main()
{
    freopen("a","r",stdin);
    //freopen("wa","w",stdout);
    Node *root=Create(retange(0,0,20001,20001));
    retange r;
    int op,x,y,n;
    while(gets(s))
    {
        if(s[0]=='E')
        {
            C=mem;
            root=Create(retange(0,0,20001,20001));
            continue;
        }
        if(s[0]=='I')
        {
            op=1;
            continue;
        }
        if(s[0]=='Q')
        {
            op=0;
            continue;
        }
        if(op)
        {
            sscanf(s,"%d%d%d",&x,&y,&n);
            Update(x,y,n,root);
        }
        else
        {
            r.rd(s);
            printf("%lld\n",Query(r,root));
        }
    }
    return 0;
}


本遗传算法由12个M文件组成,其中Genetic.m包含了主函数,其余文件均为包含子函数的文件,由主函数调用。下面对包含子函数的文件进行一一说明。 function Population = PopulationInitialize( MemberLength,MemberNumber ) 此函数返回一群二进制编码的初始染色体(MemberNumber* MemberLength的矩阵,不同的行代表不同的染色体),参数MemberNumber, MemberLength分别指定了染色体的数目和每个染色体的长度。 function PopulationFitness = Fitness( PopulationCode,FunctionFitness,MinX,MaxX,MemberLength ) 此函数返回每个染色体的适应值, 参数PopulationCode包含了染色体群体,参数FunctionFitness指定了计算适应度的函数(也即目标函数), 为一字符串,MinX,MaxX两个参数指定了自变量的区间,MemberLength依然是染色体长度。 function PopulationData = Translate( PopulationCode,MinX,MaxX,MemberLength ) 此函数是Fitness的子函数,用来计算二进制编码的染色体所对应的十进制数。 function PopulationFitness = Transfer( PopulationCode,,FunctionFitnessMinX,MaxX,MemberLength ) 此函数是Fitness的子函数,计算在自变量去某个值时的目标函数值。 function PopulationFitnessF = FitnessF( PopulationFitness,Fmin ) 此函数根据每个染色体的目标函数值,计算其适应值。 function PopulationProbability = Probability( PopulationFitness ) 此函数根据染色体的适应值,计算染色体的生存概率。 function [ NewPopulationIncludeMax,CurrentBest,EachGenMaxFitness ] = Elitist( Population,PopulationFitness,MemberLength ) 此函数根据“适者生存”的原则,淘汰不适者,然后更新染色体群。 function NewPopulation = Mutation( Population,MutationProbability ) 此函数根据变异概率,是染色体发生变异,把变异后的染色体群作为新的染色体群。 function NewPopulation = Select( Population,PopulationProbability,MemberNumber ) 此函数起着“择优保留”的作用。 function NewPopulation = Crossing( Population,FunctionFitness,MinX,MaxX,MemberLength ) 此函数完成染色体交叉互换的过程。 在CommandWindow中输入命令: >>[ Count,Result,BestMember ] = Genetic( 22,6,'sin(x)',-1,2,-2,0.01,50 ).参数含义如下: 染色体群体一共有6个,每个染色体长度为22,目标函数为sin(x),搜索区间为[-1,2],Fmin=-2,变异概率为0.01,遗传代数为40。 返回值含义如下: 遗传代数50代,在遗传到第50代时,自变量为1.5502,目标函数值为 0.9998.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值