高手
/************************************************************** Problem: 1062 User: lxy8584099 Language: C++ Result: Accepted Time:4248 ms Memory:71916 kb ****************************************************************/ /* 所有的事件按照输入顺序依次发生 搞了半天不需要可持续。。。 首先看题解 对于每一个云 有(出现时间,范围,运动方向) 因为运动是往返的 存在周期性 把往右移动的云看做+len位置后 向左移动 所以周期为 2*len 所以对于所有的 t和 t%(2*len) 效果是一样的 而且询问和add cut都是按时间来的 所以我们可以将一个云表示为 (云的左端运动到左边界的时间 ,云的长度) 放进二位坐标系 对于add 可以得到一个新的云的坐标为 ( (Ti-Li*Di)%(2*len) ,Ri-Li ) 记录下改颜色对应的坐标 方便删除 放进二位的树状数组 对于cut 时间都没作用 因为任何时候 云的颜色互异 直接在二维树状数组里删除对应颜色的坐标 对于ask (t,l,r) 因为云是往返运动 所以 (t,l,r)的覆盖面积是关于x=len对称的 先考虑x<=len的情况 考虑重合 x较大的时候和其重合的概率较小 因为此时左端点就很大 可能经过一段时间后左端点任然在r的右边 就一定不会有重合 因此 要满足 x-t<=r => x<=t+r 即左端点左移t和单位要在r的左边 同样的 x较小的时候重合概率也很小 因为此时左端点碰到左边也右移 时间足够长就可能移到r的右边 所以要满足 t-x<=r => x>=t-r 综上 t-r<=x<=t+r 左端点满足此条件是可能重合 如果该云长度过小也可能不重合 已经满足左端点<=r 如果右端点>=l 则一定有重合 而 该云从开始运动 t 的时间 距离左边界 |x-t| 所以 length>=l-|x-t| 才能保右端点>=l 画出来的图像很奇葩 可以补全为一个平行四边形 虽然面积变大了 但是点指挥出现在合法的面积内 不影响答案 对于存在( y=-x+k ) 的平行四边形 我们把坐标变为 (x,x+y) 对于存在( y=x+k ) 的平行四边形 我们把坐标变为 (x,y-x+len*2) +是为了避免出现负数 然后维护两种个扭曲的坐标系 所以树状数组修改的时候要修改两种 Qwq 注意 树状数组没法保存下标为0的信息 下标都后移一位 r==len 一条直线上的点会被重复计算 判重 */ #include<bits/stdc++.h> #define lowbit(x) ((x)&(-x)) using namespace std; const int N=2005,M=1000010; int n,len,len2,len4; // 表示 2倍的len 4倍的len int s[2][N][N<<1],x[M],y[M]; void add(int k,int a,int b,int c) { a++;b++; for(int i=a;i<=len2;i+=lowbit(i)) for(int j=b;j<=len4;j+=lowbit(j)) s[k][i][j]+=c; // 因为第二维有+len2 所以要循环到len4 } int sum(int k,int a,int b) { a++;b++; int res=0; if(a<=0||b<=0) return 0; // 判断合法 if(a>len2) a=len2; if(b>len4) b=len4; // 约数在点集范围内 for(int i=a;i;i-=lowbit(i)) for(int j=b;j;j-=lowbit(j)) res+=s[k][i][j]; return res; } int calc(int k,int x1,int y1,int x2,int y2) { return sum(k,x2,y2)-sum(k,x2,y1-1) -sum(k,x1-1,y2)+sum(k,x1-1,y1-1); } int main() { scanf("%d%d",&n,&len);; len2=(len<<1);len4=(len2<<1); while(n--) { int op,t,c,l,r,d; scanf("%d",&op); if(op==1) { scanf("%d%d%d%d%d",&t,&c,&l,&r,&d); x[c]=((t-l*d)%len2+len2)%len2; y[c]=r-l; add(0,x[c],x[c]+y[c],1); add(1,x[c],-x[c]+y[c]+len2,1); } else if(op==2) { scanf("%d%d%d",&t,&l,&r); t%=len2; int res=0,flag=(r==len); // 特殊情况 res+=calc(0,t,l+t,t+r,len4); res+=calc(0,0,l+t-len2,t+r-len2-flag,len4); res+=calc(1,t-r+len2+flag,l-t,len2,len4); res+=calc(1,t-r,l-t+len2,t-1,len4); printf("%d\n",res); } else { scanf("%d%d",&t,&c); // 时间递增 t没用。。。 add(0,x[c],x[c]+y[c],-1); add(1,x[c],-x[c]+y[c]+len2,-1); } } return 0; }