现在的位置: 首页 > 综合 > 正文

crisis(卓亮)

2018年01月15日 ⁄ 综合 ⁄ 共 4587字 ⁄ 字号 评论关闭

http://www.tsinsen.com/ViewGProblem.html?gpid=-1000001307

【题意】

有一些编号为1..n的点,每个都有其初始坐标,有六类操作

Move i j a b 编号i到编号j的点移动一个(a,b)的向量

Patrol i j a 编号i到编号j的点绕原点逆时针旋转a(弧度制)

Lurk i j 编号i到编号j的点全部坐标变为(0,0)

Cancel a 撤销最后a次操作

Redo a 重做最后a次操作

Ask i 询问第i个点的坐标

数据不会进行不合法的操作,比如

Cancel 3

Move 1 1 1 1

Redo 2

【输入】

第一行一个n

接下来n行每行一个点的初始坐标

之后一行是个q,表示操作数

接下来每行一个操作

【输出】

对于Ask 操作,输出答案,误差小于0.0001即视为正确,有check。

这个询问只询问一个点……记录下对于每个点的操作就可以知道这个点的坐标了……

不过这个也询问不了一段区间……问区间问什么啊

对于Move操作,还是很好想到如何处理的吧

关键在于Patrol操作了

假设旋转角度为a,当前与x正半轴的夹角为b,距原点的距离为r=sqrt(x^2+y^2)

旋转前坐标为(r cos(b),r sin (b))

旋转后坐标为(r cos(a+b),r sin(a+b))

作为一个高中生,自然可以将其展开

旋转后坐标即为(r(cos(a)cos(b)-sin(a)sin(b)),r(sin(a)cos(b)+cos(a)sin(b)))=(cos(a)x-sin(a)y,sin(a)x+cos(a)y)

这么一来,就比较容易想到矩阵乘法了

假设不考虑Cancel和Redo的操作

用一个线段树来描述对于每个点的操作就好了,每个节点记录一个矩阵,询问一个节点的时候,只要把访问过的矩阵乘起来就好了

不过矩阵具有结合律,不具有交换律,所以维护矩阵的顺序性很重要,所以访问一个节点的话先下移懒标记,然后再进行插入操作

询问的话,询问过程中不要下传懒标记,把路过的节点的矩阵从底到顶乘起来就好了

接下来解决如何支持Cancel和Redo操作

仔细想想的话,Cancel就是回到过去线段树的某个状态,Redo就是再回去

这样我们把线段树所有状态记录下来不就好了吗

这个不可能吗……这个当然可能,一切的一切都开始于范浩强冬令营讲稿提到的一个概念 《函数性编程》

进行一个操作,新的线段树和原来的线段树有什么区别呢,区别在于有几个节点信息不一样

具体是几个节点呢,就是访问过的节点,最多logn个

那么我们可以把这些节点复制一份,连接上原来不需要修改的节点

这样每个节点可能有多个父亲节点,但子节点是唯一的……

即从上到下查询线段树得到的树是唯一的,即只要记录下每个状态的根节点,就可以查询到这个状态的树的信息……等价于记录了线段树的所有状态

这样就解决了这道题

函数性编程是十分前沿的一种思路,感觉高端选手都对此有很多的看法,需要注意吧

{$inline on}
program crisis;
uses
  math;
const
  eps=1e-10;
  maxn=3000000;
type
  matrix=array [1..3,1..3] of double;
var
  now,tot,n,q,i,j,k:longint;
  a,b:double;
  root:array [0..50001] of longint;
  x,y:array [0..20001] of double;
  belong,left,right:array [0..maxn] of longint;
  mat:array [0..maxn] of matrix;
  squ:matrix;
  order:char;

function matrixmul (a,b:matrix):matrix;inline;
var
  ans:matrix;
  i,j,k:longint;
begin
  fillchar(ans,sizeof(ans),0);
  for i:=1 to 3 do
    for k:=1 to 3 do
      if abs(a[i,k])>eps then
        for j:=1 to 3 do
          ans[i,j]:=ans[i,j]+a[i,k]*b[k,j];
  exit(ans);
end;

procedure maketree (s,e,now:longint);
var
  mid:longint;
begin
  belong[now]:=0;
  for mid:=1 to 3 do
    mat[now][mid,mid]:=1;
  if s=e then exit;
  mid:=(s+e) div 2;
  inc(tot);
  left[now]:=tot;
  maketree(s,mid,tot);
  inc(tot);
  right[now]:=tot;
  maketree(mid+1,e,tot);
end;

procedure update (now:longint);inline;
begin
  if left[now]=0 then exit;
  if belong[left[now]]<>belong[now] then
    begin
      inc(tot);
      mat[tot]:=mat[left[now]];
      left[tot]:=left[left[now]];
      right[tot]:=right[left[now]];
      belong[tot]:=belong[now];
      left[now]:=tot;
    end;
  mat[left[now]]:=matrixmul(mat[left[now]],mat[now]);
  if belong[right[now]]<>belong[now] then
    begin
      inc(tot);
      mat[tot]:=mat[right[now]];
      left[tot]:=left[right[now]];
      right[tot]:=right[right[now]];
      belong[tot]:=now;
      right[now]:=tot;
    end;
  mat[right[now]]:=matrixmul(mat[right[now]],mat[now]);
  fillchar(mat[now],sizeof(mat[now]),0);
  mat[now][1,1]:=1;
  mat[now][2,2]:=1;
  mat[now][3,3]:=1;
end;

procedure insert (s,e,l,r,last,now:longint);
var
  mid:longint;
begin
  update(last);
  mat[now]:=mat[last];
  if (s=l)and(e=r) then
    begin
      mat[now]:=matrixmul(mat[now],squ);
      left[now]:=left[last];
      right[now]:=right[last];
      exit;
    end;
  mid:=(l+r) div 2;
  if e<=mid then
    begin
      inc(tot);
      left[now]:=tot;
      belong[tot]:=now;
      mat[tot]:=mat[left[last]];
      right[now]:=right[last];
      insert(s,e,l,mid,left[last],left[now]);
    end
            else
  if s>mid then
    begin
      left[now]:=left[last];
      inc(tot);
      right[now]:=tot;
      belong[tot]:=belong[now];
      mat[tot]:=mat[right[last]];
      insert(s,e,mid+1,r,right[last],right[now])
    end
           else
    begin
      inc(tot);
      left[now]:=tot;
      belong[tot]:=now;
      mat[tot]:=mat[left[last]];
      inc(tot);
      right[now]:=tot;
      belong[tot]:=belong[now];
      mat[tot]:=mat[right[last]];
      insert(s,mid,l,mid,left[last],left[now]);
      insert(mid+1,e,mid+1,r,right[last],right[now]);
    end;
end;

function find (x,l,r,now:longint):matrix;
begin
  if l=r then exit(mat[now]);
  if x<=(l+r) div 2 then
    exit(matrixmul(find(x,l,(l+r) div 2,left[now]),mat[now]))
                    else
    exit(matrixmul(find(x,(l+r) div 2 +1,r,right[now]),mat[now]));
end;

begin
  read(n);
  for i:=1 to n do
    read(x[i],y[i]);
  maketree(1,n,0);
  readln(q);
  while q>0 do
    begin
      dec(q);
      read(order);
      case order of
        'M':begin
              read(order,order,order);
              read(i,j,a,b);
              fillchar(squ,sizeof(squ),0);
              squ[1,1]:=1;
              squ[2,2]:=1;
              squ[3,3]:=1;
              squ[3,1]:=a;
              squ[3,2]:=b;
              inc(tot);
              inc(now);
              root[now]:=tot;
              belong[tot]:=now;
              insert(i,j,1,n,root[now-1],root[now]);
            end;
        'P':begin
              read(order,order,order,order,order);
              read(i,j,a);
              fillchar(squ,sizeof(squ),0);
              squ[1,1]:=cos(a);
              squ[2,1]:=-sin(a);
              squ[1,2]:=sin(a);
              squ[2,2]:=cos(a);
              squ[3,3]:=1;
              inc(tot);
              inc(now);
              root[now]:=tot;
              belong[tot]:=now;
              insert(i,j,1,n,root[now-1],root[now]);
            end;
        'L':begin
              read(order,order,order);
              read(i,j);
              fillchar(squ,sizeof(squ),0);
              squ[3,3]:=1;
              inc(tot);
              inc(now);
              root[now]:=tot;
              belong[tot]:=now;
              insert(i,j,1,n,root[now-1],root[now]);
            end;
        'C':begin
              read(order,order,order,order,order);
              read(i);
              now:=now-i;
            end;
        'R':begin
              read(order,order,order);
              read(i);
              now:=now+i;
            end;
        'A':begin
              read(order,order);
              read(i);
              squ:=find(i,1,n,root[now]);
              writeln(x[i]*squ[1,1]+y[i]*squ[2,1]+squ[3,1]:0:5,' ',
              x[i]*squ[1,2]+y[i]*squ[2,2]+squ[3,2]:0:5);
            end;
      end;
      readln;
    end;
end.
【上篇】
【下篇】

抱歉!评论已关闭.