Bzoj2752: [HAOI2012]高速公路(road)

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\n",ans/GCD,tem/GCD);
129         }
130     }
131 }
View Code

 

posted @ 2019-07-25 06:22  Al_Ca  阅读(127)  评论(0编辑  收藏  举报
ヾ(≧O≦)〃嗷~