原题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2752
高速公路(road)
Description
Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站。
Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1~N,从收费站i行驶到i+1(或从i+1行驶到i)需要收取Vi的费用。高速路刚建成时所有的路段都是免费的。
政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。
无聊的小A同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的l,r(l
Input
第一行2个正整数N,M,表示有N个收费站,M次调整或询问。
接下来M行,每行将出现以下两种形式中的一种。
C l r v 表示将第l个收费站到第r个收费站之间的所有道路的通行费全部增加v
Q l r 表示对于给定的l,r,要求回答小A的问题
所有C与Q操作中保证1<=l
Output
对于每次询问操作回答一行,输出一个既约分数
若答案为整数a,输出a/1
Sample Input
4 5
C 1 4 2
C 1 2 -1
Q 1 2
Q 2 4
Q 1 4
Sample Output
1/1
8/3
17/6
HINT
数据规模
所有C操作中的v的绝对值不超过10000
在任何时刻任意道路的费用均为不超过10000的非负整数
所有测试点的详细情况如下表所示
Test N M
1 =10 =10
2 =100 =100
3 =1000 =1000
4 =10000 =10000
5 =50000 =50000
6 =60000 =60000
7 =70000 =70000
8 =80000 =80000
9 =90000 =90000
10 =100000 =100000
题解
先是题意一直没读懂,手动模拟一直都没过样例的 83 8 3 ,最后发现修改操作其实是左闭右开的。。。(-1Day)
码完代码又特么一直爆 long long l o n g l o n g ,调了半天线段树发现是预处理的时候爆了。。。(-1Day)
这么道垃圾题居然耗了我两天,真的日狗。。。
事实证明,不要老想着去用数据结构维护些骚东西,先老老实实推式子。
先把读进来的
r−=1
r
−
=
1
,左闭右开真的坑。容易发现,对于
[l,r]
[
l
,
r
]
中的每个收费站,我们可以单独统计贡献,计算有几个区间覆盖了它:
因为 vi v i 前面的系数都是确定值,可以预处理出来,就能方便的统计区间加对维护信息的影响(具体可以看代码),所以三个东西都是可以直接维护的。
最后除的时候记得分母是 (r−l+22) ( r − l + 2 2 ) 。
代码
#include<bits/stdc++.h>
#define ll long long
#define ls v<<1
#define rs ls|1
using namespace std;
const int M=4e5+5;
struct sd{ll ans,ansi,ansii;};
sd operator +(sd a,sd b){return (sd){a.ans+b.ans,a.ansi+b.ansi,a.ansii+b.ansii};}
ll sum[M],tag[M],sumi[M],sumii[M],prei[M],preii[M],n,m;
char ch[2];
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void up(int v){sum[v]=sum[ls]+sum[rs],sumi[v]=sumi[ls]+sumi[rs],sumii[v]=sumii[ls]+sumii[rs];}
void push(int v,int le,int ri)
{
int mid=le+ri>>1;
tag[ls]+=tag[v],tag[rs]+=tag[v];
sum[ls]+=tag[v]*(mid-le+1),sum[rs]+=tag[v]*(ri-mid);
sumi[ls]+=tag[v]*(prei[mid]-prei[le-1]),sumi[rs]+=tag[v]*(prei[ri]-prei[mid]);
sumii[ls]+=tag[v]*(preii[mid]-preii[le-1]),sumii[rs]+=tag[v]*(preii[ri]-preii[mid]);
tag[v]=0;
}
void add(int v,int le,int ri,int lb,int rb,int d)
{
if(lb<=le&&ri<=rb)
{tag[v]+=d,sum[v]+=1ll*(ri-le+1)*d,sumi[v]+=(prei[ri]-prei[le-1])*d,sumii[v]+=(preii[ri]-preii[le-1])*d;return;}
int mid=le+ri>>1;push(v,le,ri);
if(lb<=mid)add(ls,le,mid,lb,rb,d);
if(mid<rb)add(rs,mid+1,ri,lb,rb,d);
up(v);
}
sd ask(int v,int le,int ri,int lb,int rb)
{
if(lb<=le&&ri<=rb)return (sd){sum[v],sumi[v],sumii[v]};
int mid=le+ri>>1;sd ans;push(v,le,ri);
ans.ans=ans.ansi=ans.ansii=0;
if(lb<=mid)ans=ask(ls,le,mid,lb,rb);
if(mid<rb)ans=ans+ask(rs,mid+1,ri,lb,rb);
up(v);return ans;
}
void in(){scanf("%d%d",&n,&m);}
void ac()
{
int l,r,v;sd p;ll ans,g,x;
for(int i=1;i<=n;++i)prei[i]=prei[i-1]+i,preii[i]=preii[i-1]+1ll*i*i;
for(int i=1;i<=m;++i)
{
scanf("%s%d%d",ch,&l,&r);r-=1;
if(ch[0]=='C'){scanf("%d",&v);add(1,1,n,l,r,v);}
else p=ask(1,1,n,l,r),x=1ll*(r-l+2)*(r-l+1)/2,ans=1ll*(l+r)*p.ansi-p.ansii+1ll*(r+1)*(1-l)*p.ans,g=gcd(ans,x),
printf("%lld/%lld\n",ans/g,x/g);
}
}
int main(){in();ac();}