BZOJ 2752 高速公路(road)(线段树)
2013-12-04 16:44
211 查看
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2752
题意:给出一个数列A,维护两种操作:
(1)将区间[L,R]之内的所有数字增加det;
(2)给出区间[L,R],在该区间内任意选出两个位置l和r(L<=l<=r<=R),[l,r]的费用为该区间的数字之和。求费用的期望。
思路:对于区间[L,R],长度len=(R-L+1),可知不同的区间种类有(len+1)*len/2种,那么接下来就是计算所有区间下的数字和的和S。我们发现:
![](http://img.blog.csdn.net/20130819162333640?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hhb2JhaW1pbmd0aWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
接下来我们看对于这个S我们在修改时怎么维护它?对于区间[L,R],我们设置参数sum,Lsum,Rsum,t,p,size:
![](http://img.blog.csdn.net/20130819162849109?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hhb2JhaW1pbmd0aWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
那么对于区间[L,mid],[mid+1,R]以及区间[L,R],我们设其分别为p、q、a,那么区间合并为:
![](http://img.blog.csdn.net/20130819163749218?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hhb2JhaW1pbmd0aWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
对于区间增加x:
![](http://img.blog.csdn.net/20130819163402421?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hhb2JhaW1pbmd0aWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
struct node
{
int L,R;
i64 sum,Lsum,Rsum,S,det,t,p,size;
void add(i64 x)
{
det+=x;
sum+=x*size;
Lsum+=t*x;
Rsum+=t*x;
S+=x*p;
}
};
node a[N<<2];
i64 get(i64 n)
{
return n*(n+1)*(n+1)/2-n*(n+1)*(2*n+1)/6;
}
i64 get1(i64 n)
{
return n*(n+1)/2;
}
void build(int t,int L,int R)
{
a[t].L=L;
a[t].R=R;
a[t].size=R-L+1;
a[t].t=get1(R-L+1);
a[t].p=get(R-L+1);
a[t].sum=a[t].Lsum=a[t].Rsum=a[t].S=0;
a[t].det=0;
if(L==R) return;
int mid=(L+R)>>1;
build(t*2,L,mid);
build(t*2+1,mid+1,R);
}
void pushUp(node &a,node p,node q)
{
if(a.L==a.R) return;
a.sum=p.sum+q.sum;
a.Lsum=p.Lsum+q.Lsum+q.sum*p.size;
a.Rsum=q.Rsum+p.Rsum+p.sum*q.size;
a.S=p.S+p.Lsum*q.size+q.S+q.Rsum*p.size;
}
void pushDown(int t)
{
if(a[t].L==a[t].R) return;
if(a[t].det)
{
a[t*2].add(a[t].det);
a[t*2+1].add(a[t].det);
a[t].det=0;
}
}
void update(int t,int L,int R,i64 x)
{
if(a[t].L==L&&a[t].R==R)
{
a[t].add(x);
return;
}
pushDown(t);
int mid=(a[t].L+a[t].R)>>1;
if(R<=mid) update(t*2,L,R,x);
else if(L>mid) update(t*2+1,L,R,x);
else
{
update(t*2,L,mid,x);
update(t*2+1,mid+1,R,x);
}
pushUp(a[t],a[t*2],a[t*2+1]);
}
node getSum(int t,int L,int R)
{
if(a[t].L==L&&a[t].R==R) return a[t];
pushDown(t);
node l,r,ans;
int mid=(a[t].L+a[t].R)>>1;
if(R<=mid) ans=getSum(t*2,L,R);
else if(L>mid) ans=getSum(t*2+1,L,R);
else
{
l=getSum(t*2,L,mid);
r=getSum(t*2+1,mid+1,R);
ans.L=L;
ans.R=R;
ans.size=R-L+1;
pushUp(ans,l,r);
}
pushUp(a[t],a[t*2],a[t*2+1]);
return ans;
}
int n,m;
i64 Gcd(i64 x,i64 y)
{
if(y==0) return x;
return Gcd(y,x%y);
}
int main()
{
RD(n,m);
build(1,1,n-1);
int L,R;
i64 x,ans,S,k;
char op[5];
while(m--)
{
RD(op);
if(op[0]=='C')
{
RD(L,R); R--;
RD(x);
update(1,L,R,x);
}
else
{
RD(L,R); R--;
ans=getSum(1,L,R).S;
S=get1(R-L+1);
k=Gcd(ans,S);
ans/=k; S/=k;
printf("%lld/%lld\n",ans,S);
}
}
}
题意:给出一个数列A,维护两种操作:
(1)将区间[L,R]之内的所有数字增加det;
(2)给出区间[L,R],在该区间内任意选出两个位置l和r(L<=l<=r<=R),[l,r]的费用为该区间的数字之和。求费用的期望。
思路:对于区间[L,R],长度len=(R-L+1),可知不同的区间种类有(len+1)*len/2种,那么接下来就是计算所有区间下的数字和的和S。我们发现:
接下来我们看对于这个S我们在修改时怎么维护它?对于区间[L,R],我们设置参数sum,Lsum,Rsum,t,p,size:
那么对于区间[L,mid],[mid+1,R]以及区间[L,R],我们设其分别为p、q、a,那么区间合并为:
对于区间增加x:
struct node
{
int L,R;
i64 sum,Lsum,Rsum,S,det,t,p,size;
void add(i64 x)
{
det+=x;
sum+=x*size;
Lsum+=t*x;
Rsum+=t*x;
S+=x*p;
}
};
node a[N<<2];
i64 get(i64 n)
{
return n*(n+1)*(n+1)/2-n*(n+1)*(2*n+1)/6;
}
i64 get1(i64 n)
{
return n*(n+1)/2;
}
void build(int t,int L,int R)
{
a[t].L=L;
a[t].R=R;
a[t].size=R-L+1;
a[t].t=get1(R-L+1);
a[t].p=get(R-L+1);
a[t].sum=a[t].Lsum=a[t].Rsum=a[t].S=0;
a[t].det=0;
if(L==R) return;
int mid=(L+R)>>1;
build(t*2,L,mid);
build(t*2+1,mid+1,R);
}
void pushUp(node &a,node p,node q)
{
if(a.L==a.R) return;
a.sum=p.sum+q.sum;
a.Lsum=p.Lsum+q.Lsum+q.sum*p.size;
a.Rsum=q.Rsum+p.Rsum+p.sum*q.size;
a.S=p.S+p.Lsum*q.size+q.S+q.Rsum*p.size;
}
void pushDown(int t)
{
if(a[t].L==a[t].R) return;
if(a[t].det)
{
a[t*2].add(a[t].det);
a[t*2+1].add(a[t].det);
a[t].det=0;
}
}
void update(int t,int L,int R,i64 x)
{
if(a[t].L==L&&a[t].R==R)
{
a[t].add(x);
return;
}
pushDown(t);
int mid=(a[t].L+a[t].R)>>1;
if(R<=mid) update(t*2,L,R,x);
else if(L>mid) update(t*2+1,L,R,x);
else
{
update(t*2,L,mid,x);
update(t*2+1,mid+1,R,x);
}
pushUp(a[t],a[t*2],a[t*2+1]);
}
node getSum(int t,int L,int R)
{
if(a[t].L==L&&a[t].R==R) return a[t];
pushDown(t);
node l,r,ans;
int mid=(a[t].L+a[t].R)>>1;
if(R<=mid) ans=getSum(t*2,L,R);
else if(L>mid) ans=getSum(t*2+1,L,R);
else
{
l=getSum(t*2,L,mid);
r=getSum(t*2+1,mid+1,R);
ans.L=L;
ans.R=R;
ans.size=R-L+1;
pushUp(ans,l,r);
}
pushUp(a[t],a[t*2],a[t*2+1]);
return ans;
}
int n,m;
i64 Gcd(i64 x,i64 y)
{
if(y==0) return x;
return Gcd(y,x%y);
}
int main()
{
RD(n,m);
build(1,1,n-1);
int L,R;
i64 x,ans,S,k;
char op[5];
while(m--)
{
RD(op);
if(op[0]=='C')
{
RD(L,R); R--;
RD(x);
update(1,L,R,x);
}
else
{
RD(L,R); R--;
ans=getSum(1,L,R).S;
S=get1(R-L+1);
k=Gcd(ans,S);
ans/=k; S/=k;
printf("%lld/%lld\n",ans,S);
}
}
}
相关文章推荐
- linux下磁盘报警脚本
- RadioButton总结
- Android TextView使用HTML处理字体样式、显示图片等
- linux下mysql的root密码忘记解决方
- SequenceInputStream----合并流
- Oracle rpad函数和lpad函数
- c#和JS数据加密
- Yii中的CCheckBoxColumn在widget中的用法
- 纯css的防止图片撑破页面的代码(图片自动缩放)
- HDU 4747 Mex(线段树)
- 使用Xcode和Instruments调试解决iOS内存泄露
- shell 往awk 中传值
- Android 圆形 ImageView
- AndroidAnnotations——Enhance custom classes 优化自定义类
- 排序是我曾经的朋友
- 【CCS仿真】用matlab把CCS保存的32位16进制的数据转换为十进制的数
- wpf 自定义窗口,最大化时不覆盖任务栏
- CyberArticle(网文快捕)上传文件提示‘许可不足’
- 花名册
- Android TextView中文字通过SpannableString来设置超链接、颜色、字体等属性