0
点赞
收藏
分享

微信扫一扫

洛谷 P2221 [HAOI2012] 高速公路


题目描述

Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站。

Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1~N,从收费站i行驶到i+1(或从i+1行驶到i)需要收取Vi的费用。高速路刚建成时所有的路段都是免费的。

政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。

无聊的小A同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的l,r(l < r),在第l个到第r个收费站里等概率随机取出两个不同的收费站a和b,那么从a行驶到b将期望花费多少费用呢?

输入输出格式

输入格式:
第一行2个正整数N,M,表示有N个收费站,M次调整或询问

接下来M行,每行将出现以下两种形式中的一种

C l r v 表示将第l个收费站到第r个收费站之间的所有道路的通行费全部增加v

Q l r 表示对于给定的l,r,要求回答小A的问题

所有C与Q操作中保证1<=l < r<=N

输出格式:
对于每次询问操作回答一行,输出一个既约分数

若答案为整数a,输出a/1

输入输出样例

输入样例#1:
4 5
C 1 4 2
C 1 2 -1
Q 1 2
Q 2 4
Q 1 4
输出样例#1:
1/1
8/3
17/6
说明

所有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

【分析】
用线段树维护三个值
sum
id[l]*key[l]+…+id[r]*key​​r​​
id[l]^2*key[l]+…+id[r]^2*key​​r​​
然后列个式子就可以推出答案了…
以前想用splay维护这个东西,结果没有搞出来qwq,前前后后废了两个多小时qwq

【代码】

#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=200005;
int n,m;
struct tree {int l,r,id;ll mark,sum,sum_1,sum_2;} t[mxn<<2];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
inline void update(int num)
{
t[num].sum=t[num<<1].sum+t[num<<1|1].sum;
t[num].sum_1=t[num<<1].sum_1+t[num<<1|1].sum_1;
t[num].sum_2=t[num<<1].sum_2+t[num<<1|1].sum_2;
}
inline void ope(int num,ll c)
{
ll l=t[num].l,r=t[num].r;
t[num].mark+=c;
t[num].sum+=(ll)(r-l+1)*c;
t[num].sum_1+=(l+r)*(r-l+1)*c/2;
t[num].sum_2+=c*(r*(r+1)*(r+r+1)/6-l*(l-1)*(l+l-1)/6);
}
inline void pushdown(int num)
{
if(t[num].mark)
{
if(t[num].l==t[num].r) return;
ope(num<<1,t[num].mark),ope(num<<1|1,t[num].mark);
t[num].mark=0;
}
}
inline void build(int num,int l,int r)
{
t[num].l=l,t[num].r=r;
if(l==r) return;
int mid=l+r>>1;
build(num<<1,l,mid);
build(num<<1|1,mid+1,r);
update(num);
}
inline void add(int num,int L,int R,int c)
{
if(L<=t[num].l && t[num].r<=R)
{
ope(num,c);return;
}
pushdown(num);
if(L<=t[num<<1].r) add(num<<1,L,R,c);
if(R>=t[num<<1|1].l) add(num<<1|1,L,R,c);
update(num);
}
inline ll query0(int num,int L,int R)
{
ll ans=0;
if(L<=t[num].l && t[num].r<=R)
return t[num].sum;
pushdown(num);
if(L<=t[num<<1].r) ans+=query0(num<<1,L,R);
if(R>=t[num<<1|1].l) ans+=query0(num<<1|1,L,R);
return ans;
}
inline ll query1(int num,int L,int R)
{
ll ans=0;
if(L<=t[num].l && t[num].r<=R)
return t[num].sum_1;
pushdown(num);
if(L<=t[num<<1].r) ans+=query1(num<<1,L,R);
if(R>=t[num<<1|1].l) ans+=query1(num<<1|1,L,R);
return ans;
}
inline ll query2(int num,int L,int R)
{
ll ans=0;
if(L<=t[num].l && t[num].r<=R)
return t[num].sum_2;
pushdown(num);
if(L<=t[num<<1].r) ans+=query2(num<<1,L,R);
if(R>=t[num<<1|1].l) ans+=query2(num<<1|1,L,R);
return ans;
}
inline ll gcd(ll x,ll y)
{
if(x<y) swap(x,y);
return x%y==0?y:gcd(y,x%y);
}
int main()
{
// freopen("roadxw.in","r",stdin);
// freopen("roadxw.out","w",stdout);
int i,j,w,x,y;
char s[3];
n=read(),m=read();
build(1,1,n-1);
while(m--)
{
scanf("%s",s);
if(s[0]=='C')
{
x=read(),y=read(),w=read();
add(1,x,y-1,w);
}
else
{
x=read(),y=read();
ll zero=query0(1,x,y-1),one=query1(1,x,y-1),two=query2(1,x,y-1);
// printf("test=%lld %lld %lld\n",zero,one,two);
ll ans=(ll)zero*y*(1-x)+(ll)one*(x+y-1)-two,mu=(ll)(y-x+1)*(ll)(y-x)/2;
if(ans==0)
{
printf("0/1\n");
continue;
}
ll yue=gcd(ans,mu);
ans/=yue,mu/=yue;
printf("%lld/%lld\n",ans,mu);
}
}
return 0;
}
/*
4 5
C 1 4 2
C 1 2 -1
Q 1 2
Q 2 4
Q 1 4
*/


举报

相关推荐

0 条评论