zoukankan      html  css  js  c++  java
  • 【2020NOI.AC省选模拟#2】A. 旋转

    题目链接

    原题解:

    把每个点的坐标视为复数,那么每次询问就是区间求平均数(先求和然后除以个数)。一个点绕着原点旋转就是乘以$(cos 60^circ +isin 60^circ)$。

    一个点绕着某点$A$旋转可以理解为先减去点$A$的坐标,再绕原点旋转,再加上点$A$的坐标。

    最终变成用线段树维护复数的序列,支持区间加上一个数和乘上一个数和区间求和,使用打标记的线段树解决。

    补充:

    在?为什么卡空间?

    原题解提供的线段树做法很NICE,然而直接上线段树会被卡空间。然后我百度到了深度好文,学习了线段树少开空间的方法。

    首先来个结论:

    长度为$n$的序列会形成$2n-1$个节点的线段树。

    为啥呢?观察一下线段树的结构,发现有底下的$n$个叶子,之后两个子节点用一个父节点合并。由$n$个连通块合并为一个块需要$n-1$次,所以总共有$2n-1$个节点。

    然后我们考虑用DFS序给节点编号。 发现对于节点$i$代表$[l,r]$,左儿子的编号就是$i+1$,然后左子树占用了连续的$2(mid-l+1)-1$个编号,那么右儿子编号就是$i+2(mid-l+1)-1+1=i+2(mid-l+1)$。

    然后就过了。打标记的线段树参考我自己的这篇博客

    噢还有一点,就是浮点数要记得重写一个等于函数,本题因为有封装,不容易注意到这个问题,但这确实会导致RE。

    代码(100分):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    #define IL inline
    #define RG register
    #define _1 first
    #define _2 second
    using namespace std;
    typedef double DB;
    #define RI RG int
    #define RD RG DB
    #define RP RG Pr
    #define RM RG Mrk
    const int N=1e5;
    const DB Pi=acos(-1);
    const DB eps=1e-6;
    
        int n,q;
        
    struct Pr{
        DB x,y;
        Pr(RD x=0,RD y=0):x(x),y(y){}
    }mul1=Pr(1,0),add0=Pr(0,0)
    ,rot=Pr(cos(Pi/3),sin(Pi/3))
    ,a[N+3],sum[N*2+3];
    
    IL bool eql(RD x,RD y){
        return fabs(x-y)<eps;
    }
    
    IL bool operator==(RP x,RP y){
        return eql(x.x,y.x)&&eql(x.y,y.y);
    }
    
    IL Pr operator*(RP x,RP y){
        return Pr(x.x*y.x-x.y*y.y,x.y*y.x+x.x*y.y);
    }
    
    IL Pr operator*(RD x,RP y){
        return Pr(x*y.x,x*y.y);
    }
    
    IL Pr operator+(RP x,RP y){
        return Pr(x.x+y.x,x.y+y.y);
    }
    
    struct Mrk{
        Pr m,a;
        Mrk(RP m=mul1,RP a=add0):m(m),a(a){}
    }non,tag[N*2+3];
    
    IL bool operator==(RM x,RM y){
        return x.m==y.m&&x.a==y.a;
    }
    
    IL int ls(RI i){return i+1;}
    IL int rs(RI i,RI l,RI mid){
        return i+((mid-l+1)<<1);
    }
    
    IL void f(RI i,RI l,RI r,RM opt){
        if(opt==non)
            return ;
        
        sum[i]=opt.m*sum[i]+(DB)(r-l+1)*opt.a;
        
        Mrk tmp=tag[i];
        tag[i]=Mrk(opt.m*tmp.m,opt.m*tmp.a+opt.a);
        
    }
    
    IL void spread(RI i,RI l,RI r){
        RI mid=(l+r)>>1;
        f(ls(i),l,mid,tag[i]);
        f(rs(i,l,mid),mid+1,r,tag[i]);
        tag[i]=non;
        
    }
    
    void build(RI i,RI l,RI r){
        tag[i]=non;
        if(l==r){
            sum[i]=a[l];
            return ;
            
        }
        
        RI mid=(l+r)>>1;
        build(ls(i),l,mid);
        build(rs(i,l,mid),mid+1,r);
        sum[i]=sum[ls(i)]+sum[rs(i,l,mid)];
        
    }
    
    void mdf(RI i,RI l,RI r,RI ql,RI qr,RM opt){
        if(ql<=l&&r<=qr){
            f(i,l,r,opt);
            return ;
            
        }
        
        spread(i,l,r);
        RI mid=(l+r)>>1;
        if(ql<=mid)
            mdf(ls(i),l,mid,ql,qr,opt);
        if(qr>mid)
            mdf(rs(i,l,mid),mid+1,r,ql,qr,opt);
        sum[i]=sum[ls(i)]+sum[rs(i,l,mid)];
        
    }
    
    Pr qry(RI i,RI l,RI r,RI ql,RI qr){
        if(qr<l||r<ql)
            return add0;
        if(ql<=l&&r<=qr)
            return sum[i];
        
        spread(i,l,r);
        RI mid=(l+r)>>1;
        if(qr<=mid)
            return qry(ls(i),l,mid,ql,qr);
        if(ql>mid)
            return qry(rs(i,l,mid),mid+1,r,ql,qr);
        return qry(ls(i),l,mid,ql,qr)
              +qry(rs(i,l,mid),mid+1,r,ql,qr);
        
    }
    
    int main(){
        scanf("%d%d",&n,&q);
        for(RI i=1;i<=n;i++)
            scanf("%lf%lf",&a[i].x,&a[i].y);
            
        build(1,1,n);
        for(RI i=1,l,r;i<=q;i++){
            scanf("%d%d",&l,&r);
            
            RP tmp=1.0/(r-l+1)*qry(1,1,n,l,r);
            printf("%.10lf %.10lf
    ",tmp.x,tmp.y);
            mdf(1,1,n,l,r,Mrk(mul1,-1.0*tmp));
            mdf(1,1,n,l,r,Mrk(rot,add0));
            mdf(1,1,n,l,r,Mrk(mul1,tmp));
            
        }
        
        for(RI i=1;i<=n;i++){
            a[i]=qry(1,1,n,i,i);
            printf("%.10lf %.10lf
    ",a[i].x,a[i].y);
            
        }
    
        return 0;
    
    }
    View Code
  • 相关阅读:
    与众不同 windows phone (50)
    与众不同 windows phone (49)
    重新想象 Windows 8.1 Store Apps (93)
    重新想象 Windows 8.1 Store Apps 系列文章索引
    重新想象 Windows 8.1 Store Apps (92)
    重新想象 Windows 8.1 Store Apps (91)
    重新想象 Windows 8.1 Store Apps (90)
    重新想象 Windows 8.1 Store Apps (89)
    重新想象 Windows 8.1 Store Apps (88)
    重新想象 Windows 8.1 Store Apps (87)
  • 原文地址:https://www.cnblogs.com/Hansue/p/13031051.html
Copyright © 2011-2022 走看看