zoukankan      html  css  js  c++  java
  • BZOJ4066: 简单题

    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。
    接下来每行一个操作。每条命令除第一个数字之外,
    均要异或上一次输出的答案last_ans,初始时last_ans=0。
     

    Output

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

    Sample Input

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

    Sample Output

    3
    5

    HINT

    数据规模和约定

    1<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。

    样例解释见OJ2683
    新加数据一组,但未重测----2015.05.24

    隔壁AKC一眼CDQ发现是在线又一眼树套树发现MLE了。。

    实在不是很会搞,分割平面那就KD-tree走一波

    至于加值,那就是插点,查找就类似于线段树维护下子树和不行递归找

    然后T掉了:多次加点使树的结构失衡,退化为平方级算法

    那就暴力重构,每到一定范围就像替罪羊树一样强行拆开重构

    //MT_LI
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    struct KDT{
        int lc,rc,s,sum;
        int mn[2],mx[2],d[2];
    }tr[500010];
    void update(int x)
    {
        int lc=tr[x].lc,rc=tr[x].rc;
        if(lc)
        {
            tr[x].mn[0]=min(tr[x].mn[0],tr[lc].mn[0]);
            tr[x].mn[1]=min(tr[x].mn[1],tr[lc].mn[1]);
            tr[x].mx[0]=max(tr[x].mx[0],tr[lc].mx[0]);
            tr[x].mx[1]=max(tr[x].mx[1],tr[lc].mx[1]);
            tr[x].sum+=tr[lc].sum;
        }
        if(rc)
        {
            tr[x].mn[0]=min(tr[x].mn[0],tr[rc].mn[0]);
            tr[x].mn[1]=min(tr[x].mn[1],tr[rc].mn[1]);
            tr[x].mx[0]=max(tr[x].mx[0],tr[rc].mx[0]);
            tr[x].mx[1]=max(tr[x].mx[1],tr[rc].mx[1]);
            tr[x].sum+=tr[rc].sum;
        }
    }
    int cmpd,root;
    bool cmp(KDT a,KDT b){return a.d[cmpd]<b.d[cmpd] || a.d[cmpd]==b.d[cmpd]&&a.d[cmpd^1]<b.d[cmpd^1];}
    void ins(int now)
    {
        int p=root;
        while(1)
        {
            if(tr[p].mx[0]<tr[now].mx[0])tr[p].mx[0]=tr[now].mx[0];
            if(tr[p].mx[1]<tr[now].mx[1])tr[p].mx[1]=tr[now].mx[1];
            if(tr[p].mn[0]>tr[now].mn[0])tr[p].mn[0]=tr[now].mn[0];
            if(tr[p].mn[1]>tr[now].mn[1])tr[p].mn[1]=tr[now].mn[1];
            tr[p].sum+=tr[now].sum;
            if(tr[now].d[cmpd]<tr[p].d[cmpd])
            {
                if(tr[p].lc==0){tr[p].lc=now;return ;}
                else p=tr[p].lc;
            }
            else
            {
                if(tr[p].rc==0){tr[p].rc=now;return ;}
                else p=tr[p].rc;
            }
            cmpd^=1;
        }
    }
    int find(int x,int x1,int y1,int x2,int y2)
    {
        if(tr[x].mn[0]>x2||tr[x].mn[1]>y2||tr[x].mx[0]<x1||tr[x].mx[1]<y1)return 0;
        if(tr[x].mx[0]<=x2&&tr[x].mx[1]<=y2&&tr[x].mn[0]>=x1&&tr[x].mn[1]>=y1)return tr[x].sum;
        int tot=0;
        if(tr[x].d[0]>=x1&&tr[x].d[1]>=y1&&tr[x].d[0]<=x2&&tr[x].d[1]<=y2)tot=tr[x].s;
        if(tr[x].lc)tot+=find(tr[x].lc,x1,y1,x2,y2);
        if(tr[x].rc)tot+=find(tr[x].rc,x1,y1,x2,y2);
        return tot;
    }
    int rebuild(int l,int r,int d)
    {
        int mid=(l+r)/2,now;
        now=mid;cmpd=d;
        nth_element(tr+l,tr+mid,tr+r+1,cmp);
        tr[now].mx[0]=tr[now].mn[0]=tr[now].d[0];
        tr[now].mx[1]=tr[now].mn[1]=tr[now].d[1];
        tr[now].sum=tr[now].s;
        if(l<mid)tr[now].lc=rebuild(l,mid-1,d^1);
        if(mid<r)tr[now].rc=rebuild(mid+1,r,d^1);
        update(now);
        return now;
    }
    int ans=0;
    int main()
    {
        int n;int cnt=0;
        scanf("%d",&n);root=0;
        while(1)
        {
            int op;
            scanf("%d",&op);
            if(op==3)break;
            if(op==1)
            {
                ++cnt;
                scanf("%d%d%d",&tr[cnt].d[0],&tr[cnt].d[1],&tr[cnt].s);
                tr[cnt].d[0]^=ans;tr[cnt].d[1]^=ans;tr[cnt].s^=ans;
                tr[cnt].mx[0]=tr[cnt].mn[0]=tr[cnt].d[0];
                tr[cnt].mx[1]=tr[cnt].mn[1]=tr[cnt].d[1];
                tr[cnt].sum=tr[cnt].s;
                if(cnt%10000==0)
                {
                    for(int i=1;i<=cnt;i++)tr[i].lc=tr[i].rc=0;
                    root=rebuild(1,cnt,0);
                    continue;
                }
                if(root==0)root=cnt;
                else cmpd=0,ins(cnt);
            }
            else
            {
                int x1,x2,y1,y2;
                scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                x1^=ans;x2^=ans;y1^=ans;y2^=ans;
                ans=find(root,x1,y1,x2,y2);
                printf("%d
    ",ans);            
            }
        }
        return 0;
    }
  • 相关阅读:
    hdu 1151
    DAG的最小路径覆盖和二分图的最大匹配
    二部图 最小点覆盖集与最大匹配的关系
    sdut 2151
    sdut Emergency
    作业
    Node.prototype.contains
    微博登录
    markdown
    Object.observe
  • 原文地址:https://www.cnblogs.com/MT-LI/p/9791657.html
Copyright © 2011-2022 走看看