• 题解【[Ynoi2012]NOIP2015洋溢着希望】


    [ exttt{Preface} ]

    第二道 Ynoi 的题,纪念一下。

    这可能是我唯一可以自己做的 Ynoi 题了。

    [ exttt{Description} ]

    维护一个长度为 (n) 的数列 (a),支持两种操作:

    • 1 l r v(a_l,a_{l+1},...,a_r) 分别加上 (v)
    • 2 l r 询问 (sumlimits_{i=l}limits^{r}sin(a_i))

    [ exttt{Solution} ]

    • 区间修改和区间查询使我们想到线段树。

    • 尝试在线段树上维护一个区间 (sin) 和。

    • 我们发现,区间加的时候,原来的 (sin(a_i)) 都变成了 (sin(a_i+v)) ,不易直接维护。

    • 考虑这两个公式:

      [sin(a+v)=sin acos v+cos asin v ]

      [cos(a+v)=cos acos v-sin a sin v ]

    • 显然区间加将区间 ([l,r])(sin) 和从 (sumlimits_{i=l}limits^{r}sin(a_i)) 变成了 (sumlimits_{i=l}limits^{r}sin(a_i+v)) ,进一步,有:

      [sumlimits_{i=l}limits^{r}sin a_i cos v+ cos a_i sin v ]

    [cos v sumlimits_{i=l}limits^{r}sin a_i + sin vsumlimits_{i=l}limits^{r}cos a_i ]

    • 于是我们可以再维护一个区间 (cos) 和, 区间加对 ([l,r])(cos) 和的影响为:

    [cos v sumlimits_{i=l}limits^{r} cos a_i -sin vsumlimits_{i=l}limits^{r} sin a_i ]

    • 套用上述公式更新区间 (sin) 和以及区间 (cos) 和即可,记得打好标记。

    [ exttt{Code} ]

    #include<cstdio>
    #include<cmath>
    
    #define RI register int
    
    using namespace std;
    
    namespace IO
    {
        static char buf[1<<20],*fs,*ft;
        inline char gc()
        {
            if(fs==ft)
            {
    			ft=(fs=buf)+fread(buf,1,1<<20,stdin);
    			if(fs==ft)return EOF;
            }
            return *fs++;
        }
        #define gc() getchar()
    	inline int read()
    	{
    		int x=0,f=1;char s=gc();
    		while(s<'0'||s>'9'){if(s=='-')f=-f;s=gc();}
    		while(s>='0'&&s<='9'){x=x*10+s-'0';s=gc();}
    		return x*f;
    	}
    }using IO::read;
    
    const int N=200100;
    
    int n,m;
    
    int a[N];
    
    struct SegmentTree{
    	int l,r;
    	double sinv,cosv;
    	long long tag;
    }t[N*4];
    
    void upd(int p)
    {
    	t[p].sinv=t[p*2].sinv+t[p*2+1].sinv;
    	t[p].cosv=t[p*2].cosv+t[p*2+1].cosv;
    }
    
    void spread(int p)
    {
    	if(t[p].tag)
    	{
    		double sina,cosa,sinx=sin(t[p].tag),cosx=cos(t[p].tag);
    		sina=t[p*2].sinv,cosa=t[p*2].cosv;
    		t[p*2].sinv=sina*cosx+cosa*sinx;
    		t[p*2].cosv=cosa*cosx-sina*sinx;
    		sina=t[p*2+1].sinv,cosa=t[p*2+1].cosv;
    		t[p*2+1].sinv=sina*cosx+cosa*sinx;
    		t[p*2+1].cosv=cosa*cosx-sina*sinx;
    		t[p*2].tag+=t[p].tag;
    		t[p*2+1].tag+=t[p].tag;
    		t[p].tag=0;
    	}
    }
    
    void build(int p,int l,int r)
    {
    	t[p].l=l,t[p].r=r;
    	if(l==r)
    	{
    		t[p].sinv=sin(a[l]),t[p].cosv=cos(a[l]);
    		return;
    	}
    	int mid=(l+r)/2;
    	build(p*2,l,mid);
    	build(p*2+1,mid+1,r);
    	upd(p);
    }
    
    void change(int p,int l,int r,int val)
    {
    	if(l<=t[p].l&&t[p].r<=r)
    	{
    		double sina=t[p].sinv,cosa=t[p].cosv,sinx=sin(val),cosx=cos(val);
    		t[p].sinv=sina*cosx+cosa*sinx;
    		t[p].cosv=cosa*cosx-sina*sinx;
    		t[p].tag+=val;
    		return;
    	}
    	spread(p);
    	int mid=(t[p].l+t[p].r)/2;
    	if(l<=mid)
    		change(p*2,l,r,val);
    	if(mid<r)
    		change(p*2+1,l,r,val);
    	upd(p);
    }
    
    double ask(int p,int l,int r)
    {
    	if(l<=t[p].l&&t[p].r<=r)return t[p].sinv;
    	spread(p);
    	int mid=(t[p].l+t[p].r)/2;
    	double val=0;
    	if(l<=mid)
    		val+=ask(p*2,l,r);
    	if(mid<r)
    		val+=ask(p*2+1,l,r);
    	return val;
    }
    
    int main()
    {
    	n=read();
    
    	for(RI i=1;i<=n;i++)
    		a[i]=read();
    
    	build(1,1,n);
    
    	m=read();
    
    	while(m--)
    	{
    		int opt=read(),l=read(),r=read();
    
    		switch(opt)
    		{
    			case 1:{
    
    				double val; scanf("%lf",&val);
    				change(1,l,r,val);
    
    				break;
    			}
    
    			case 2:{
    
    				printf("%.1lf
    ",ask(1,l,r));
    
    				break;
    			}
    		}
    	}
    
    	return 0;
    }
    

    [ exttt{Thanks} exttt{for} exttt{watching} ]

  • 相关阅读:
    hdu 刷题记录
    HDU step by step
    Codeforces Round #260 (Div. 2) B. Fedya and Maths
    Codeforces Round #260 (Div. 2) A. Laptops
    UVALive 6662 TheLastAnt
    UVALive 6661 Equal Sum Sets
    Codeforces Round #253 (Div. 2) A. Anton and Letters
    wikioi 3130 CYD刷题(背包)
    wikioi 1014 装箱问题(背包)
    [转]很特别的一个动态规划入门教程
  • 原文地址:https://www.cnblogs.com/cjtcalc/p/12324869.html
Copyright © 2020-2023  润新知