zoukankan      html  css  js  c++  java
  • [Luogu 2221] HAOI2012 高速公路

    [Luogu 2221] HAOI2012 高速公路

    <题目链接>


    比较容易看出的线段树题目。

    由于等概率,期望便转化为 子集元素和/子集个数。

    每一段l..r中,子集元素和为:

    (sum w_{i}(i-l+1)(r-i)) //((i-l+1)(r-i))是每个数用到的次数

    (=sum w_{i}((r-lr)+(l+r-1)i-i^{2}))

    (=(r-lr)sum w_{i}+(l+r-1)sum i imes w_{i}-sum i^{2} imes w_{i})

    由此观之,线段树需要维护(sum w_{i})v[0](sum i imes w_{i})v[1](sum i^{2} imes w_{i})v[2]

    有这样一个神奇的公式:

    (1^{2}+2^{2}+dots+n^{2}=n(n+1)(2n+1)/6)

    所以,在进行Update操作时,设size=r-l+1,改变量为v

    v[0]+=v*size;
    v[1]+=v*size*(l+r)>>1;
    v[2]+=v*(r*(r+1)*((r<<1)+1)-(l-1)*l*((l<<1)-1))/6LL;
    

    记得开long long以及各种强制转int为long long!隐式类型转换简直天坑。

    线段树基础不扎实的我这题调了一天…

    #include <cstdio>
    #include <cstring>
    const int MAXN=100010;
    int n,m;
    class SegmentTree
    {
    	public:
    		SegmentTree(void)
    		{
    			memset(s,0,sizeof s);
    		}
    		void BuildTree(int i,int l,int r)
    		{
    			s[i].l=l,s[i].r=r;
    			if(l==r)
    				return;
    			int j=i<<1,mid=l+r>>1;
    			BuildTree(j,l,mid),BuildTree(j+1,mid+1,r);
    		}
    		void Add(int i,int l,int r,long long v)
    		{
    			if(l==s[i].l && r==s[i].r)
    			{
    				Update(i,v);
    				return;
    			}
    			if(s[i].l!=s[i].r && s[i].lazy)
    				PushDown(i);
    			int j=i<<1,mid=s[i].l+s[i].r>>1;
    			if(r<=mid)
    				Add(j,l,r,v);
    			else if(l>mid)
    				Add(j+1,l,r,v);
    			else
    				Add(j,l,mid,v),Add(j+1,mid+1,r,v);
    			PushUp(i);
    		}
    		void Ans(long long l,long long r)
    		{
    			long long t,ans,cnt=(r-l+1)*(r-l)>>1LL,sum[3];
    			for(int i=0;i<3;++i)
    				sum[i]=Sum(1,l,r-1,i);
    			ans=sum[0]*(r-l*r)+sum[1]*(l+r-1)-sum[2];
    			t=GCD(ans,cnt);
    			printf("%lld/%lld
    ",ans/t,cnt/t);
    		}
    	private:
    		struct node
    		{
    			int l,r;
    			long long lazy,v[3];
    		}s[MAXN<<2];
    		long long GCD(long long x,long long y)
    		{
    			return !y ? x : GCD(y,x%y);
    		}
    		void Update(int i,long long v)
    		{
    			long long l=s[i].l,r=s[i].r,size=r-l+1;
    			s[i].lazy+=v;
    			s[i].v[0]+=v*size;
    			s[i].v[1]+=v*size*(l+r)>>1;
    			s[i].v[2]+=v*(r*(r+1)*((r<<1)+1)-(l-1)*l*((l<<1)-1))/6LL;
    		}
    		void PushUp(int i)
    		{
    			for(int j=0;j<3;++j)
    				s[i].v[j]=s[i<<1].v[j]+s[i<<1|1].v[j];
    		}
    		void PushDown(int i)
    		{
    			int j=i<<1;
    			Update(j,s[i].lazy),Update(j+1,s[i].lazy);
    			s[i].lazy=0;
    		}
    		long long Sum(int i,int l,int r,int k)
    		{
    			if(l==s[i].l && r==s[i].r)
    				return s[i].v[k];
    			if(s[i].l!=s[i].r && s[i].lazy)
    				PushDown(i);
    			int j=i<<1,mid=s[i].l+s[i].r>>1;
    			if(r<=mid)
    				return Sum(j,l,r,k);
    			else if(l>mid)
    				return Sum(j+1,l,r,k);
    			else
    				return Sum(j,l,mid,k)+Sum(j+1,mid+1,r,k);
    		}
    }T;
    int main(int argc,char *argv[])
    {
    	scanf("%d %d",&n,&m);
    	T.BuildTree(1,1,n-1);
    	for(int i=1,l,r,v;i<=m;++i)
    	{
    		char c;
    		scanf("
    %c %d %d",&c,&l,&r);
    		if(c=='C')
    		{
    			scanf("%d",&v);
    			T.Add(1,l,r-1,v);
    		}
    		else
    			T.Ans(l,r);
    	}
    	return 0;
    }
    

    谢谢阅读。

  • 相关阅读:
    VS2010中经常使用的快捷键
    IE无法打开internet网站已终止操作的解决的方法
    Spring3.0 AOP 具体解释
    Java 反射机制[Method反射]
    软件測试自学指南---从入门到精通
    Java中Map的使用
    tracert路由跟踪命令分析判断
    C++ Primer 学习笔记_32_STL实践与分析(6) --再谈string类型(下)
    ORACLE触发器具体解释
    Androidclient推断server是否开启 HttpHostException解决方式
  • 原文地址:https://www.cnblogs.com/Capella/p/8460048.html
Copyright © 2011-2022 走看看