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

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2752

首先以点代边,设第i个点表示i-1>i。

对于每个点算贡献,假设这个点是p,当前询问区间是[l,r],那么它的贡献为2*(p-l)*(r-p+1)*vp/((r-l)*(r-l+1)),打开合并同类项得到-(l+l*r)*vp+(l+r+1)*p*vp-p^2*vp

那么我们只要快速处理出区间的vp,p*vp,p^2*vp然后就可以用线段树维护了。

1^2+2^2+……+n^2=n*(n+1)*(2*n+1)/6

(写代码半个小时,打错一行代码调一晚上,真是太弱了TAT。。。由于我懒得不行于是所有变量都开LL,好像也不会特别慢嘛TAT

#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 100500
using namespace std;
typedef long long ll;
struct data{ll s[4],tag,size,l,r;
}t[maxn*5];
ll n,m;
ll ans,s;
ll read(){
    ll x=0,f=1; char ch=getchar();
    while (!isdigit(ch)) {
        if (ch=='-') f=-1; ch=getchar();
    }
    while (isdigit(ch)){
        x=x*10+ch-'0'; ch=getchar();
    }
    return x*f;
}
ll gcd(ll x,ll y){
    if (y==0) return x;
    return gcd(y,x%y);
}
void print(ll ans,ll s){
    ll k=gcd(ans,s);
    printf("%lld/%lld\n",ans/k,s/k);
}
void build(ll i,ll l,ll r){
    t[i].l=l; t[i].r=r; t[i].tag=0; t[i].size=(r-l+1);
    if (l==r) return ;
    ll mid=(l+r)/2;
    build(i*2,l,mid); build(i*2+1,mid+1,r);
}
ll get(ll n){
    return n*(n+1)*(2*n+1)/6;
}
void update(ll i,ll z){
    t[i].tag+=z;
    t[i].s[1]+=t[i].size*z;
    t[i].s[2]+=t[i].size*(t[i].l+t[i].r)/2*z;
    t[i].s[3]+=(get(t[i].r)-get(t[i].l-1))*z; 
}
void up(ll i){
    rep(j,1,3) t[i].s[j]=t[i*2].s[j]+t[i*2+1].s[j];
}
void Down(ll i){
    update(i*2,t[i].tag); update(i*2+1,t[i].tag);
    t[i].tag=0;
}
void add(ll i,ll x,ll y,ll z){
    ll l=t[i].l,r=t[i].r,mid=(l+r)/2;
    if (l==x&&r==y) {
        update(i,z); return;
    }
    if (t[i].tag) Down(i);
    if (x<=mid) add(i*2,x,min(mid,y),z);
    if (y>=mid+1) add(i*2+1,max(x,mid+1),y,z);
    up(i);
}
ll ask(ll i,ll x,ll y,ll k){
    ll l=t[i].l,r=t[i].r,mid=(l+r)/2;
    ll ans=0;
    if (l==x&&y==r) return t[i].s[k];
    if (t[i].tag) Down(i);
    if (x<=mid) ans+=ask(i*2,x,min(mid,y),k);
    if (y>=mid+1) ans+=ask(i*2+1,max(x,mid+1),y,k);
    return ans;
}
int main(){
    n=read(); m=read();
    build(1,1,n);
    rep(i,1,m){
        ll x,y,l,r; ll z;
        char ch=getchar(); while (ch!='C'&&ch!='Q') ch=getchar();
        if (ch=='C'){
            x=read(); y=read(); scanf("%lld",&z);
            add(1,x+1,y,z);
        }
        else {
            l=read(); r=read();
            ans=(-(l+l*r)*ask(1,l+1,r,1)+(l+r+1)*ask(1,l+1,r,2)-ask(1,l+1,r,3));
            s=(r-l)*(r-l+1)/2;
            print(ans,s);
        }
    }
    return 0;
}

 

posted on 2015-11-27 22:07  ctlchild  阅读(322)  评论(0编辑  收藏  举报

导航