zoukankan      html  css  js  c++  java
  • 【BZOJ1062】糖果雨(NOI2008)-数形结合+二维树状数组

    测试地址:糖果雨
    做法:本题需要用到数形结合+二维树状数组。
    这题看上去非常没有思路,因此我们来一步一步整理一下思路。
    首先,我们要发现线段的颜色互不相同,并且移动的速度相等,这就说明它们的运动是周期性的,并且周期都是2len。原先我们要用一个三元组(t,l,r)来表示一条线段,而发现了上面的共性之后,我们就可以用一个二元组(time,length)来表示一条线段,具体来说,time是指在一个周期内,线段的左端点到达0的时刻,而length则是线段的长度。这样我们就可以将一条线段用一个二维平面上的点表示出来了。
    接下来,考虑询问(t,l,r),首先将t2len取模,然后观察一条线段(time,length)与该询问相交的条件:trtimet+r,并且lengthl|timet|。我们可以在二维平面上画出一个奇怪的图形,而我们要求的就是这个图形内的点数。
    然而这个奇怪的图形非常难算,我们可以把这个图形补成一些平行四边形,然而还是很难算,因此我们分两种情况,一种是往右下斜的平行四边形,一种是往右上斜的平行四边形,我们用两个扭曲的坐标系来把平行四边形扭成矩形计算,对于第一种平行四边形,进行变换(x,y)>(x,y+x)即可,而对于第二种平行四边形,进行变换(x,y)>(x,yx+2len)(为了保证坐标非负所以加了2len)即可。那么我们就可以用二维树状数组来维护单点修改,子矩阵查询了,时间复杂度为O(nlog2len)。具体的求子矩阵端点的式子可以看代码。
    有一点小细节要注意,当r=len时,有一条直线上的点会被重复计算,要注意去重。还有,树状数组不能处理坐标为0的情况,将所有坐标+1即可。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,len,len2,len4;
    int sum[2][4010][4010],x[1000010],y[1000010];
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    int add(int type,int x,int y,int d)
    {
        x++,y++;
        for(int i=x;i<=len2;i+=lowbit(i))
            for(int j=y;j<=len4;j+=lowbit(j))
                sum[type][i][j]+=d;
    }
    
    int Sum(int type,int x,int y)
    {
        x++,y++;
        if (x<=0||y<=0) return 0;
        if (x>len2) x=len2;
        if (y>len4) y=len4;
        int ans=0;
        for(int i=x;i;i-=lowbit(i))
            for(int j=y;j;j-=lowbit(j))
                ans+=sum[type][i][j];
        return ans;
    }
    
    int calc(int type,int x1,int y1,int x2,int y2)
    {
        return Sum(type,x2,y2)-Sum(type,x2,y1-1)-Sum(type,x1-1,y2)+Sum(type,x1-1,y1-1);
    }
    
    int main()
    {
        scanf("%d%d",&n,&len);
        len2=(len<<1),len4=(len<<2);
        for(int i=1;i<=n;i++)
        {
            int op,t,c,l,r,d,ans;
            scanf("%d",&op);
            if (op==1)
            {
                scanf("%d%d%d%d%d",&t,&c,&l,&r,&d);
                x[c]=(t-d*l+len2)%len2;
                y[c]=r-l;
                add(0,x[c],y[c]+x[c],1);
                add(1,x[c],y[c]-x[c]+len2,1);
            }
            if (op==2)
            {
                scanf("%d%d%d",&t,&l,&r);
                t%=len2;
                ans=0;
                int flag=(r==len);
                ans+=calc(0,t,l+t,t+r,len4);
                ans+=calc(0,0,l+t-len2,t+r-len2-flag,len4);
                ans+=calc(1,t-r+len2+flag,l-t,len2,len4);
                ans+=calc(1,t-r,l-t+len2,t-1,len4);
                printf("%d
    ",ans);
            }
            if (op==3)
            {
                scanf("%d%d",&t,&c);
                add(0,x[c],y[c]+x[c],-1);
                add(1,x[c],y[c]-x[c]+len2,-1);
            }
        }
    
        return 0;
    }

    彩蛋:如果你看到了这里,告诉你一个小秘密——这是我在BZOJ上AC的第233道题目!真是个喜庆的数字……

  • 相关阅读:
    Spring MVC Ajax 嵌套表单数据的提交
    Spring MVC 过滤静态资源访问
    Spring MVC 页面跳转时传递参数
    IDEA Maven 三层架构 2、运行 springMVC
    IDEA Maven 三层架构 1、基本的Archetype 搭建
    EasyUI DataGrid 基于 Ajax 自定义取值(loadData)
    Spring MVC Ajax 复杂参数的批量传递
    Mybatis Sql片段的应用
    在 Tomcat 8 部署多端口项目
    自动升级的设计思路与实现
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793334.html
Copyright © 2011-2022 走看看