• 洛谷P2221 [HAOI2012]高速公路


    题目:P2221 [HAOI2012]高速公路

    思路:

    这道题是在线段树专题讲的,转化的思路可能自己不太容易想到,记录一下。

    难度集中在转化设问上面。问题可以简化成区间([l,r-1])的问题,实际上就是算所有子区间的区间和然后再除(C(len,2))
    我们来观察这个区间和,发现直接做貌似不太好搞,于是想到了考虑每个数对区间答案的贡献,之后可以写出(O(n))修改、查询的暴力的式子:
    (sum_{i=l}^r{s[i]*(i-l+1)*(r-i+1)*2})
    继续观察,发现式子可以拆成(s[i])(i*s[i])(i^2*s[i])的区间和的常数倍,于是就可以用区间加减的线段树搞了。

    已经讲的很清楚了。
    式子可以化为:
    (2*((l+r)sum_{i=l}^r{i*s[i]}+(r-l+1-l*r)*sum_{i=l}^r{s[i]}-sum_{i=l}^r{i^2*s[i]}))
    然后分别维护三个值:(s[i])直接维护,(i*s[i])用等差数列求和,(i^2*s[i])(sum_{i=1}^n{i^2}=frac {n(n+1)(2n+1)} 6)
    细节:边化点,维护序列长n-1;计算的时候想清楚r用不用减1;记得开longlong。
    难点:最初的思路转化:把原问题转化为计算每条边的贡献。


    Code:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll N=2e5+5;
    ll n,m,ans1,ans2,ans3;
    struct Tree{
        ll l,r,sum1,sum2,sum3,tag;
    #define l(p) (node[p].l)
    #define r(p) (node[p].r)
    #define sum1(p) (node[p].sum1)
    #define sum2(p) (node[p].sum2)
    #define sum3(p) (node[p].sum3)
    #define tag(p) (node[p].tag)
    #define ls(p) (p<<1)
    #define rs(p) (p<<1|1)
    #define len(p) (r(p)-l(p)+1)
    #define mid ((l(p)+r(p))>>1)
    }node[N<<2];
    ll calc(ll n){
        return n*(n+1)*(2*n+1)/6;
    }
    void pup(ll p){
        sum1(p)=sum1(ls(p))+sum1(rs(p));
        sum2(p)=sum2(ls(p))+sum2(rs(p));
        sum3(p)=sum3(ls(p))+sum3(rs(p));
    }
    void update(ll p,ll val){
        tag(p)+=val;
        sum1(p)+=len(p)*val;
        sum2(p)+=val*(l(p)+r(p))*len(p)/2;
        sum3(p)+=(calc(r(p))-calc(l(p)-1))*val;
    }
    void pdown(ll p){
        if(tag(p)){
            update(ls(p),tag(p));
            update(rs(p),tag(p));
            tag(p)=0;
        }
    }
    void build(ll p,ll l,ll r){
        l(p)=l;r(p)=r;
        if(l==r) return;
        build(ls(p),l,mid);
        build(rs(p),mid+1,r);
    }
    void change(ll p,ll L,ll R,ll val){
        if(l(p)>R||r(p)<L) return;
        if(L<=l(p)&&r(p)<=R) return update(p,val);
        pdown(p);
        change(ls(p),L,R,val);
        change(rs(p),L,R,val);
        pup(p);
    }
    void query(ll p,ll L,ll R){
        if(l(p)>R||r(p)<L) return;
        if(L<=l(p)&&r(p)<=R) return (void) (ans1+=sum1(p),ans2+=sum2(p),ans3+=sum3(p));
        pdown(p);
        query(ls(p),L,R);
        query(rs(p),L,R);
    }
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    int main(){
        scanf("%lld%lld",&n,&m);
        build(1,1,n-1);
        char op[5]; ll l,r,val;
        for(ll i=1;i<=m;++i){
            scanf("%s",op);
            if(op[0]=='C') scanf("%lld%lld%lld",&l,&r,&val),change(1,l,r-1,val);
            else{
                scanf("%d%d",&l,&r);
                --r;
                ans1=ans2=ans3=0;
                query(1,l,r);
                ll res=(l+r)*ans2-ans3+(r-l-l*r+1)*ans1,div=(r-l+2)*(r-l+1)/2,d=gcd(res,div);
                res/=d,div/=d;
                printf("%lld/%lld
    ",res,div);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    线程TLAB区域的深入剖析
    ivotal-tc-Server与Tomcat区别
    Java线程面试题 Top 50 (转载)
    Java并发编程:Timer和TimerTask(转载)
    Java并发编程:Callable、Future和FutureTask
    Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
    Java并发编程:线程池的使用
    Java多线程与并发库高级应用-可阻塞的队列
    java多线程与并发库高级应用-工具类介绍
    Google guava工具类的介绍和使用
  • 原文地址:https://www.cnblogs.com/yu-xing/p/11245329.html
Copyright © 2020-2023  润新知