Bzoj2752: [HAOI2012]高速公路(road)
比较恶心的一道题,关键在于r的加1减1搞得很乱。所以以下的r都是原题给出的r,并没有减1。
其实这道题是一个假的期望,答案就是区间的所有子区间和除以$C_{len}^2$,然后就考虑如何求所有子区间和,
直接暴力枚举肯定不行,可以像‘树上染色’一样考虑每个点的贡献,对于点i,他的贡献为$s[i]*(i-l+1)*(r-i)$其实就是选到i点左边(包括自己)的方案数以及选到右边的方案数,乘起来就是i点作出贡献的次数,再乘上s[i].那么我们最终要求的就是$∑s[i]*(i-l+1)*(r-i)$,这样看式子当然看不出来什么,试着把它拆开,得到
$∑(l+r-1)*s[i]*i-s[i]*i^2+(r-l*r)*s[i]$,即$(l+r-1)*∑s[i]*i-∑s[i]*i^2+(r-l*r)*∑s[i]$,这样就可以用线段树维护s[i],s[i]*i,s[i]*i*i,通过普通的线段树就可以做出来了。
1 #include<iostream> 2 #include<cstdio> 3 #define int long long 4 using namespace std; 5 struct tree 6 { 7 int l,r,sum1,sum2,sum3,sumi,sumi2,la; 8 #define l(x) tr[x].l 9 #define r(x) tr[x].r 10 #define sum1(x) tr[x].sum1 11 #define sum2(x) tr[x].sum2 12 #define sum3(x) tr[x].sum3 13 #define sumi(x) tr[x].sumi 14 #define sumi2(x) tr[x].sumi2 15 #define la(x) tr[x].la 16 }tr[400010]; 17 int gcd(int a,int b){return !b?a:gcd(b,a%b);} 18 int n,m; 19 20 void pushup(int x) 21 { 22 int ls=x*2,rs=x*2+1; 23 sum1(x)=sum1(ls)+sum1(rs); 24 sum2(x)=sum2(ls)+sum2(rs); 25 sum3(x)=sum3(ls)+sum3(rs); 26 sumi(x)=sumi(ls)+sumi(rs); 27 sumi2(x)=sumi2(ls)+sumi2(rs); 28 } 29 void build(int l,int r,int x) 30 { 31 l(x)=l,r(x)=r; 32 if(l==r) 33 { 34 sumi(x)=l, 35 sumi2(x)=l*l; 36 return; 37 } 38 int mid=(l+r)>>1; 39 build(l,mid,x*2); 40 build(mid+1,r,x*2+1); 41 pushup(x); 42 } 43 void down(int x) 44 { 45 if(l(x)==r(x))return; 46 if(!la(x))return; 47 int ls=x*2,rs=x*2+1; 48 la(ls)+=la(x),la(rs)+=la(x); 49 sum1(ls)+=(r(ls)-l(ls)+1)*la(x); 50 sum1(rs)+=(r(rs)-l(rs)+1)*la(x); 51 sum2(ls)+=sumi(ls)*la(x); 52 sum2(rs)+=sumi(rs)*la(x); 53 sum3(ls)+=sumi2(ls)*la(x); 54 sum3(rs)+=sumi2(rs)*la(x); 55 la(x)=0; 56 pushup(x); 57 } 58 void add(int l,int r,int x,int y) 59 { 60 if(l(x)==r(x)) 61 { 62 sum1(x)+=y; 63 sum2(x)+=l(x)*y; 64 sum3(x)+=l(x)*l(x)*y; 65 return; 66 } 67 down(x); 68 if(l(x)>=l&&r(x)<=r) 69 { 70 la(x)+=y; 71 down(x); 72 return; 73 } 74 int mid=(l(x)+r(x))>>1; 75 if(l<=mid)add(l,r,x*2,y); 76 if(r>mid) add(l,r,x*2+1,y); 77 pushup(x); 78 } 79 int ask1(int l,int r,int x) 80 { 81 down(x); 82 if(l(x)>=l&&r(x)<=r) 83 return sum1(x); 84 int ans=0,mid=(l(x)+r(x))>>1; 85 if(l<=mid)ans+=ask1(l,r,x*2); 86 if(r>mid) ans+=ask1(l,r,x*2+1); 87 return ans; 88 } 89 int ask2(int l,int r,int x) 90 { 91 down(x); 92 if(l(x)>=l&&r(x)<=r)return sum2(x); 93 int ans=0,mid=(l(x)+r(x))>>1; 94 if(l<=mid)ans+=ask2(l,r,x*2); 95 if(r>mid) ans+=ask2(l,r,x*2+1); 96 return ans; 97 } 98 int ask3(int l,int r,int x) 99 { 100 down(x); 101 if(l(x)>=l&&r(x)<=r)return sum3(x); 102 int ans=0,mid=(l(x)+r(x))>>1; 103 if(l<=mid)ans+=ask3(l,r,x*2); 104 if(r>mid) ans+=ask3(l,r,x*2+1); 105 return ans; 106 } 107 signed main() 108 { 109 cin>>n>>m;n--; 110 build(1,n,1); 111 char op[3];int l,r,v; 112 for(int i=1;i<=m;i++) 113 { 114 cin>>op>>l>>r; 115 if(op[0]=='C') 116 { 117 cin>>v; 118 add(l,r-1,1,v); 119 } 120 else 121 { 122 int ans=(l+r-1)*ask2(l,r-1,1)-ask3(l,r-1,1)+(r-l*r)*ask1(l,r-1,1); 123 // cout<<ask2(l,r-1,1)<<" "<<ask3(l,r-1,1) <<" "<<ask1(l,r-1,1)<<endl; 124 int len=r-l+1,tem; 125 tem=len*(len-1)/2; 126 int GCD=gcd(ans,tem); 127 if(ans==0)puts("0/1"); 128 else printf("%lld/%lld ",ans/GCD,tem/GCD); 129 } 130 } 131 }