bzoj2752 [HAOI2012]高速公路(road)

线段树好题。

很容易求出要维护的东西的公式,给线段标号,设x,y为左右线段标号,那么其中出现的总和就是Σc[i]*((i-x)*(y-i)+(y-x)),拆开就是Σ(y-x-y*x)*c[i]+(x+y)*i*c[i]-i2*c[i].

于是只要维护∑c[i],∑i*c[i],∑i2*c[i]就行了。

我一开始想偷懒写bit发现用了bit以后维护的和会升至3维,(⊙o⊙)…三维求和,略难搞,只好放弃。

那么就是线段树,用一个求和公式就行了。

看来以后要多练练线段树了,实在是偷懒偷的太多了......

road
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 #define maxn 800000
 7 #define inf 2147483647
 8 using namespace std;
 9 long long key[4][maxn],cov[maxn];
10 int n,m;
11 long long ll,rr;
12 
13 inline void cover(int x,long long l,long long r,long long z)
14 {
15     key[1][x]+=z*(r-l+1);
16     key[2][x]+=z*(l+r)*(r-l+1)/2;
17     key[3][x]+=z*(r*(r+1)*(2*r+1)-(l-1)*l*(2*l-1))/6;
18 }
19 
20 inline void down(int x,int l,int r)
21 {
22     int mid=(l+r)>>1;
23     cov[x*2]+=cov[x];
24     cov[x*2+1]+=cov[x];
25     cover(x*2,l,mid,cov[x]);
26     cover(x*2+1,mid+1,r,cov[x]);
27     cov[x]=0;
28 }    
29     
30 inline void add(int x,int l,int r,long long z)
31 {
32     if (ll<=l&&r<=rr)
33     {
34         cov[x]+=z;
35         cover(x,l,r,z);
36         return ;
37     }
38     down(x,l,r);
39     int mid=(l+r)>>1;
40     if (ll<=mid) add(x*2,l,mid,z);
41     if (rr>mid) add(x*2+1,mid+1,r,z);
42     for (int i=1;i<=3;i++) key[i][x]=key[i][x*2]+key[i][x*2+1];
43 }
44 
45 inline long long ask(int k,int x,int l,int r)
46 {
47     long long tmp=0;
48     if (ll<=l&&r<=rr) return key[k][x];
49     down(x,l,r);
50     int mid=(l+r)>>1;
51     if (ll<=mid) tmp+=ask(k,x*2,l,mid);
52     if (rr>mid) tmp+=ask(k,x*2+1,mid+1,r);
53     for (int i=1;i<=3;i++) key[i][x]=key[i][x*2]+key[i][x*2+1];
54     return tmp;
55 }
56 
57 inline long long gcd(long long a,long long b)
58 {
59     if (a==0) return b;
60     else return gcd(b%a,a);
61 }    
62 
63 int main()
64 {
65     //freopen("road4.in","r",stdin);
66     //freopen("road.out","w",stdout);
67     scanf("%d%d",&n,&m);
68     n=n-1;
69     int x,y,z;
70     char sign;
71     for (int i=1;i<=m;i++)
72     {
73         scanf("\n%c",&sign);
74         if (sign=='C')
75         {
76             scanf("%d%d%d",&x,&y,&z);
77             ll=x; rr=y-1;
78             add(1,1,n,z);
79         }
80         else 
81         if (sign=='Q')
82         {
83             scanf("%d%d",&x,&y);
84             ll=x; rr=y-1;
85             long long a1=(rr-ll-rr*ll+1)*ask(1,1,1,n);
86             long long a2=(ll+rr)*ask(2,1,1,n);
87             long long a3=ask(3,1,1,n);
88             long long ans=a1+a2-a3;
89             long long sum=(rr-ll+1)*(rr-ll+2)/2;
90             long long tmp;
91             if (ans>sum) tmp=gcd(sum,ans); else tmp=gcd(ans,sum);
92             printf("%lld/%lld\n",ans/tmp,sum/tmp);
93         }
94     }
95     return 0;
96 }

 

转载于:https://www.cnblogs.com/zig-zag/archive/2013/05/04/3059495.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值