火神的鱼

Description

火神最爱的就是吃鱼了,所以某一天他来到了一个池塘边捕鱼。池塘可以看成一个二维的平面,而他的渔网可以看成一个与坐标轴平行的矩形。
池塘里的鱼不停地在水中游动,可以看成一些点。有的时候会有鱼游进渔网,有的时候也会有鱼游出渔网。所以火神不知道什么时候收网才可以抓住最多的鱼,现在他寻求你的帮助。
他对池塘里的每条鱼都给予了一个标号,分别从1到n标号,n表示池塘里鱼的总数。鱼的游动可以概括为两个动作:
1 l r d : 表示标号在[l,r]这个区间内的鱼向x轴正方向游动了d个单位长度。
2 l r d:表示标号在[l,r]这个区间内的鱼向y轴正方向游动了d个单位长度。
在某些时刻火神会询问你现在有多少条他关心的鱼在渔网内(边界上的也算),请你来帮助他吧。

Solution

题目简意是一些点在坐标轴的第一象限,且只会朝正方向移动,给出一个矩阵,问在若干次操作后,标号在[l,r]这个区间内的鱼有多少条在矩阵中。对于四个点,每个点开两棵线段树,一棵维护横坐标,另一棵维护纵坐标,而且只维护左下角的点的信息。因为每个点只会向正方向移动,所以一个点只会退出线段树一次,所以很好维护,计算答案只需要用好像矩阵前缀和的计算就好了。

Code

var
    mj:array[1..2,1..4] of longint=((1,3,5,7),(2,4,6,8));
    w:array[1..8] of longint;
    s:array[1..4] of longint;
    tr,bz,ans:array[1..8,1..100000] of longint;
    fx,fy:array[1..30000] of longint;
    t,n,m,i,cz,l,r,d,x,y,sum:longint;
function max(x,y:longint):longint;
begin
    if x>y then exit(x) else exit(y);
end;
procedure make(bh,l,r,wz:longint);
var mid:longint;
begin
    if l=r then
    begin
        case bh mod 2 of
            1:begin
                  tr[bh,wz]:=fx[l];
                  ans[bh,wz]:=1;
                  bz[bh,wz]:=0;
              end;
            0:begin
                  tr[bh,wz]:=fy[l];
                  ans[bh,wz]:=1;
                  bz[bh,wz]:=0;
              end;
        end;
        exit;
    end;
    mid:=(l+r)div 2;
    make(bh,l,mid,wz*2);
    make(bh,mid+1,r,wz*2+1);
    tr[bh,wz]:=max(tr[bh,wz*2],tr[bh,wz*2+1]);
    ans[bh,wz]:=ans[bh,wz*2]+ans[bh,wz*2+1];
end;
procedure down(bh,l,r,wz:longint);
begin
    if bz[bh,wz]=0 then exit;
    tr[bh,wz*2]:=tr[bh,wz*2]+bz[bh,wz];
    tr[bh,wz*2+1]:=tr[bh,wz*2+1]+bz[bh,wz];
    bz[bh,wz*2]:=bz[bh,wz*2]+bz[bh,wz];
    bz[bh,wz*2+1]:=bz[bh,wz*2+1]+bz[bh,wz];
    bz[bh,wz]:=0;
end;
procedure change(bh,l,r,wz,x,y,z:longint);
var mid:longint;
begin
    if (l=x)and(r=y) then
    begin
        tr[bh,wz]:=tr[bh,wz]+z;
        bz[bh,wz]:=bz[bh,wz]+z;
        exit;
    end;
    down(bh,l,r,wz);
    mid:=(l+r)div 2;
    if x>mid then change(bh,mid+1,r,wz*2+1,x,y,z)
    else if y<=mid then change(bh,l,mid,wz*2,x,y,z)
    else
    begin
        change(bh,l,mid,wz*2,x,mid,z);
        change(bh,mid+1,r,wz*2+1,mid+1,y,z);
    end;
    tr[bh,wz]:=max(tr[bh,wz*2],tr[bh,wz*2+1]);
    ans[bh,wz]:=ans[bh,wz*2]+ans[bh,wz*2+1];
end;
procedure del(bh,l,r,wz:longint);
var mid:longint;
begin
    if l=r then
    begin
        tr[bh,wz]:=-maxlongint;
        ans[bh,wz]:=0;
        sum:=l;
        exit;
    end;
    down(bh,l,r,wz);
    mid:=(l+r)div 2;
    if tr[bh,wz*2]<tr[bh,wz*2+1] then del(bh,mid+1,r,wz*2+1)
       else del(bh,l,mid,wz*2);
    tr[bh,wz]:=max(tr[bh,wz*2],tr[bh,wz*2+1]);
    ans[bh,wz]:=ans[bh,wz*2]+ans[bh,wz*2+1];
end;
procedure del1(bh,l,r,wz,x:longint);
var mid:longint;
begin
    if l=r then
    begin
        tr[bh,wz]:=-maxlongint;
        ans[bh,wz]:=0;
        exit;
    end;
    down(bh,l,r,wz);
    mid:=(l+r)div 2;
    if x>mid then del1(bh,mid+1,r,wz*2+1,x)
       else del1(bh,l,mid,wz*2,x);
    tr[bh,wz]:=max(tr[bh,wz*2],tr[bh,wz*2+1]);
    ans[bh,wz]:=ans[bh,wz*2]+ans[bh,wz*2+1];
end;
procedure ask(bh,l,r,wz,x,y,z:longint);
var mid:longint;
begin
    if (l=x)and(r=y) then
    begin
        s[z]:=s[z]+ans[bh,wz];
        exit;
    end;
    down(bh,l,r,wz);
    mid:=(l+r)div 2;
    if x>mid then ask(bh,mid+1,r,wz*2+1,x,y,z)
    else if y<=mid then ask(bh,l,mid,wz*2,x,y,z)
    else
    begin
        ask(bh,l,mid,wz*2,x,mid,z);
        ask(bh,mid+1,r,wz*2+1,mid+1,y,z);
    end;
end;
procedure cz1;
var i:longint;
begin
    readln(l,r,d);
    for i:=1 to 4 do
    begin
        change(mj[1,i],1,n,1,l,r,d);
        while tr[mj[1,i],1]>w[mj[1,i]] do
        begin
            del(mj[1,i],1,n,1);
            del1(mj[2,i],1,n,1,sum);
        end;
    end;
end;
procedure cz2;
var i:longint;
begin
    readln(l,r,d);
    for i:=1 to 4 do
    begin
        change(mj[2,i],1,n,1,l,r,d);
        while tr[mj[2,i],1]>w[mj[2,i]] do
        begin
            del(mj[2,i],1,n,1);
            del1(mj[1,i],1,n,1,sum);
        end;
    end;
end;
procedure cz3;
begin
    readln(l,r);
    fillchar(s,sizeof(s),0);
    ask(3,1,n,1,l,r,1);
    ask(1,1,n,1,l,r,2);
    ask(7,1,n,1,l,r,3);
    ask(5,1,n,1,l,r,4);
    writeln(s[1]-s[2]-s[3]+s[4]);
end;
begin
    readln(t);
    while t>0 do
    begin
        dec(t);
        fillchar(tr,sizeof(tr),0);
        fillchar(ans,sizeof(ans),0);
        fillchar(bz,sizeof(bz),0);
        readln(n);
        read(x,y);
        w[5]:=x;w[6]:=y;
        w[1]:=x;w[8]:=y;
        read(x,y);
        w[3]:=x;w[4]:=y;
        w[7]:=x;w[2]:=y;
        dec(w[1]);dec(w[5]);dec(w[6]);dec(w[8]);
        for i:=1 to n do readln(fx[i],fy[i]);
        for i:=1 to 8 do make(i,1,n,1);
        for i:=1 to 4 do
            while tr[mj[1,i],1]>w[mj[1,i]] do
            begin
                del(mj[1,i],1,n,1);
                del1(mj[2,i],1,n,1,sum);
            end;
        for i:=1 to 4 do
            while tr[mj[2,i],1]>w[mj[2,i]] do
            begin
                del(mj[2,i],1,n,1);
                del1(mj[1,i],1,n,1,sum);
            end;
        readln(m);
        for i:=1 to m do
        begin
            read(cz);
            case cz of
                1:cz1;
                2:cz2;
                3:cz3;
            end;
        end;
    end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值