bzoj1062【Noi2008】糖果雨

orz.....神tm数形结合题

题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1062

   

 

   插入线段,删除线段,查询区间内线段个数,线段随时间往复运动

sol:  线段肯定没法操作,考虑把线段化成点

   首先显然因为2*len是一个周期,所以t%=2*len

   因为线段有一个初始位置l,考虑将线段移动至l=0的位置,用时间和长度表示该线段

   

   插入一个点时,该点的坐标为((t-l*d)%len,r-l)

   删除一个点时,直接删除即可

   对于查询操作,t时刻与[l,r]有交的线段如下图

   

   先画出t=0时的图像,左右沿x=len对称,再右移t个单位,超过右边界的补到左边

   ....这样奇怪的图形也没法处理QAQ不过可以将其补成平行四边形

   

   还是比较难搞QAQ,然而可以通过扭曲坐标系将其化成矩形

   <len的点横坐标仍为t,纵坐标为Pi+t

   >len的点横坐标仍为t,纵坐标为Pi﹣t+2*len(为保证坐标非负)

   

   唔....然后就是平面加点,删点,查询子矩阵和QwQ用二维树状数组维护即可

   各种细节在代码里有注释

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mx=1000010;
struct Node { int x,y1,y2; } str[Mx];
int q,len,k,t,map[2][2010][4010];//因为有两种斜率,所以每个点需要记2次 
inline int lowbit(int x) { return x&(-x); }
inline void add(int c,int det)//因为树状数组不能访问0下标,需要右移一位 
{
    for(int i=str[c].x+1;i<2010;i+=lowbit(i)) 
    {
        for(int j=str[c].y1+1;j<4010;j+=lowbit(j)) map[0][i][j]+=det;
        for(int j=str[c].y2+1;j<4010;j+=lowbit(j)) map[1][i][j]+=det;
    }
}
inline int sum(int x,int y,int jud)
{
    if(x<0||y<0) return 0; x++;y++;//下标右移 
    if(x>2*len) x=(2*len)+1;
    if(y>4*len) y=(4*len)+1;
    int tmp=0;
    for(int i=x;i>0;i-=lowbit(i))
        for(int j=y;j>0;j-=lowbit(j))
            tmp+=map[jud][i][j];
    return tmp;
}
inline int area(int jud,int x1,int y1,int x2,int y2)
{
    return sum(x2,y2,jud)+sum(x1-1,y1-1,jud)-sum(x1-1,y2,jud)-sum(x2,y1-1,jud);
    //考虑下标超过2*len时要补到左边 
}
inline int solve(int t,int l,int r)
{
    int d=(r==len);//如果区间右端点为len则在直线y=len上的点只能被计算一次 
    return area(0,t,l+t,t+r,4*len)+area(0,0,l+t-2*len,t+r-2*len-d,4*len)+
           area(1,2*len-r+t+d,l-t,2*len,4*len)+area(1,t-r,l-t+2*len,t-1,4*len);
}
int main()
{
    scanf("%d%d",&q,&len);
    while(q--)
    {
        scanf("%d%d",&k,&t);
        if(k==1)
        {
            int l,r,c,d;scanf("%d%d%d%d",&c,&l,&r,&d);
            str[c].x=(t+(2*len)-(l*d))%(2*len);//2*len为一个周期 
            str[c].y1=r-l+str[c].x;
            str[c].y2=r-l-str[c].x+(2*len);//为避免下标为负所以上移2*len个单位 
            add(c,1);//加点视为单点+1 
        }
        else if(k==2)
        {
            int l,r;scanf("%d%d",&l,&r);
            printf("%d\n",solve(t%(2*len),l,r));
        }
        else
        {
            int c;scanf("%d",&c);
            add(c,-1);//删点视为单点-1 
        }
    }
    return 0;
}
posted @ 2017-01-09 10:33  Czarina  阅读(836)  评论(0编辑  收藏  举报