BZOJ2752: [HAOI2012]高速公路(road)
2752: [HAOI2012]高速公路(road)
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 608 Solved: 199
[Submit][Status]
Description
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将期望花费多少费用呢?
Input
第一行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
Output
对于每次询问操作回答一行,输出一个既约分数
若答案为整数a,输出a/1
Sample Input
C 1 4 2
C 1 2 -1
Q 1 2
Q 2 4
Q 1 4
Sample Output
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
Source
题解:
我居然不知道 i*x,i*i*x是可以用线段树维护的,我是有多sb。。。
其实看到题目就已经想到了肯定转化一下就变成了只需要维护一个和,平方和啊什么乱七八糟的东西,可是还是没想下去。。。
说下正解:
假设x到y公路是可经过的
那么 i 对答案的贡献是 v[i]*(i-x+1)*(y-i+1)=v[i]*[(y-x-x*y+1)+i*(x+y)-i*i]
所以我们需要线段树来维护 sigma v[i],sigma i*v[i],sigma i*i*v[i],
维护的时候其实很简单,我脑洞太大没去想。。。
inline void update(int k,ll z) { ll l=t[k].l,r=t[k].r; t[k].tag+=z; t[k].num[1]+=z*(r-l+1); t[k].num[2]+=z*(r+l)*(r-l+1)/2; t[k].num[3]+=z*(r*(r+1)*(2*r+1)-(l-1)*l*(2*l-1))/6; }
这样就可以了。。。
代码:
1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include<iostream> 12 13 #include<vector> 14 15 #include<map> 16 17 #include<set> 18 19 #include<queue> 20 21 #include<string> 22 23 #define inf 1000000000 24 25 #define maxn 100000+100 26 27 #define maxm 500+100 28 29 #define eps 1e-10 30 31 #define ll long long 32 33 #define pa pair<int,int> 34 35 #define for0(i,n) for(int i=0;i<=(n);i++) 36 37 #define for1(i,n) for(int i=1;i<=(n);i++) 38 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 40 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 42 43 #define mod 1000000007 44 45 using namespace std; 46 47 inline int read() 48 49 { 50 51 int x=0,f=1;char ch=getchar(); 52 53 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 54 55 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 56 57 return x*f; 58 59 } 60 struct seg{int l,r;ll num[4],tag;}t[4*maxn]; 61 int n,m;ll ans[4]; 62 void build(int k,int l,int r) 63 { 64 t[k].l=l;t[k].r=r;t[k].tag=0; 65 if(l==r)return; 66 int mid=(l+r)>>1; 67 build(k<<1,l,mid);build(k<<1|1,mid+1,r); 68 } 69 inline void update(int k,ll z) 70 { 71 ll l=t[k].l,r=t[k].r; 72 t[k].tag+=z; 73 t[k].num[1]+=z*(r-l+1); 74 t[k].num[2]+=z*(r+l)*(r-l+1)/2; 75 t[k].num[3]+=z*(r*(r+1)*(2*r+1)-(l-1)*l*(2*l-1))/6; 76 } 77 inline void pushdown(int k) 78 { 79 if(!t[k].tag)return; 80 update(k<<1,t[k].tag); 81 update(k<<1|1,t[k].tag); 82 t[k].tag=0; 83 } 84 inline void pushup(int k) 85 { 86 for1(i,3)t[k].num[i]=t[k<<1].num[i]+t[k<<1|1].num[i]; 87 } 88 void change(int k,int x,int y,ll z) 89 { 90 int l=t[k].l,r=t[k].r,mid=(l+r)>>1; 91 if(l==x&&r==y){update(k,z);return;} 92 pushdown(k); 93 if(y<=mid)change(k<<1,x,y,z); 94 else if(x>mid)change(k<<1|1,x,y,z); 95 else change(k<<1,x,mid,z),change(k<<1|1,mid+1,y,z); 96 pushup(k); 97 } 98 void query(int k,int x,int y,int z) 99 { 100 int l=t[k].l,r=t[k].r,mid=(l+r)>>1; 101 if(l==x&&r==y){ans[z]+=t[k].num[z];return;} 102 pushdown(k); 103 if(y<=mid)query(k<<1,x,y,z); 104 else if(x>mid)query(k<<1|1,x,y,z); 105 else query(k<<1,x,mid,z),query(k<<1|1,mid+1,y,z); 106 } 107 inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} 108 109 int main() 110 111 { 112 113 freopen("input.txt","r",stdin); 114 115 freopen("output.txt","w",stdout); 116 117 n=read()-1;m=read(); 118 build(1,1,n); 119 char ch[2]; 120 while(m--) 121 { 122 scanf("%s",ch); 123 if(ch[0]=='C') 124 { 125 int x=read(),y=read()-1;ll z=read(); 126 change(1,x,y,z); 127 } 128 else 129 { 130 int xx=read(),yy=read()-1;ll x=xx,y=yy; 131 ll sum=(y-x+1)*(y-x+2)/2; 132 for1(i,3)ans[i]=0,query(1,xx,yy,i); 133 ans[0]=(y-x-x*y+1)*ans[1]+(y+x)*ans[2]-ans[3]; 134 ll tmp=gcd(ans[0],sum); 135 printf("%lld/%lld\n",ans[0]/tmp,sum/tmp); 136 } 137 } 138 139 return 0; 140 141 }