zoukankan      html  css  js  c++  java
  • [HNOI2015]开店

    [HNOI2015]开店 

    法一

    一个点到所有点距离?

    树上路径问题,从一个点出发的

    虽然不是统计一次,虽然强制在线,点分治也可以做!

    因为可以动态点分治的分治树来搞!

    vector维护到根路径dis,按age sort之后,处理后缀和

    再维护到分治树father的贡献

    O(nlog^2n)

    代码:

    #pragma GCC optimize("O2,Ofast,inline,unroll-all-loops,-ffast-math")
    #pragma GCC target("avx,sse2,sse3,sse4,popcnt")
    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=150000+5;
    const int inf=0x3f3f3f3f;
    int n,q,A;
    int age[N];
    struct node{
        int nxt,to,val;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y,int z){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;e[cnt].val=z;hd[x]=cnt;
    }
    int sz[N],nowsz;
    struct po{
        int id,dis;
        ll bac;
        po(){}
        po(int dd,int ds){
            id=dd;dis=ds;bac=ds;
        }
        bool friend operator <(po a,po b){
            if(a.id!=b.id) return a.id<b.id;
            return a.dis<b.dis;
        }
        void op(){
            cout<<" id "<<id<<" dis "<<dis<<" bac "<<bac<<endl;
        }
    };
    vector<po>mem[N];
    int dis[N][19];
    int fa[N];
    vector<po>df[N];
    int rt;//,sz[N];
    int vis[N];
    int dep[N];
    void fin(int x,int fa){
        sz[x]=1;
        int mxsz=0;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa||vis[y]) continue;
            fin(y,x);
            sz[x]+=sz[y];
            mxsz=max(mxsz,sz[y]);
        }
        mxsz=max(mxsz,nowsz-sz[x]);
        if(mxsz<=nowsz/2){
            rt=x;
        }
    }
    void dfs2(int x,int fa,int d){
        sz[x]=1;
        if(d!=1) df[rt].push_back(po(age[x],dis[x][d-1]));
        mem[rt].push_back(po(age[x],dis[x][d]));
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa||vis[y]) continue;
            dis[y][d]=dis[x][d]+e[i].val;
            dfs2(y,x,d);
            sz[x]+=sz[y];
        }
    }
    void divi(int x,int d,int f){
    //    cout<<" divi "<<x<<" d "<<d<<" f "<<f<<" nowsz "<<nowsz<<endl;
        rt=0;
        fin(x,0);
    //    cout<<" rt "<<rt<<endl;
        dep[rt]=d;
        fa[rt]=f;
        dfs2(rt,0,d);
        if(d!=1){
            sort(df[rt].begin(),df[rt].end());
            for(reg i=df[rt].size()-2;i>=0;--i){
                df[rt][i].bac=df[rt][i+1].bac+df[rt][i].dis;
            }
        }
        sort(mem[rt].begin(),mem[rt].end());
        for(reg i=mem[rt].size()-2;i>=0;--i){
            mem[rt][i].bac=mem[rt][i+1].bac+mem[rt][i].dis;
        }
        vis[rt]=1;
        int tmp=rt;
        for(reg i=hd[tmp];i;i=e[i].nxt){
            int y=e[i].to;
            if(!vis[y]){
                nowsz=sz[y];
                divi(y,d+1,tmp);
            }
        }
    }
    ll wrk(int x,int L,int R){
        ll ret=0;
        int le=lower_bound(mem[x].begin(),mem[x].end(),po(L,-1))-mem[x].begin();
        int ri=upper_bound(mem[x].begin(),mem[x].end(),po(R,inf))-mem[x].begin();
        if(le!=mem[x].size()) ret+=mem[x][le].bac;
        if(ri!=mem[x].size()) ret-=mem[x][ri].bac;
    //    cout<<"start "<<ret<<endl;
        int st=x;
        while(fa[x]){
            int y=fa[x];
    //        cout<<" yy "<<y<<" dis "<<dis[st][dep[y]]<<endl;
    //        for(reg i=0;i<mem[y].size();++i){
    //            cout<<" i "<<i+1;mem[y][i].op();cout<<endl;
    //        }
            int le=lower_bound(mem[y].begin(),mem[y].end(),po(L,-1))-mem[y].begin();
            int ri=upper_bound(mem[y].begin(),mem[y].end(),po(R,inf))-mem[y].begin();
    //        cout<<" le ri "<<le<<" "<<ri<<endl;
            if(le!=mem[y].size()) ret+=mem[y][le].bac,ret+=(ll)(mem[y].size()-le)*dis[st][dep[y]];
            if(ri!=mem[y].size()) ret-=mem[y][ri].bac,ret-=(ll)(mem[y].size()-ri)*dis[st][dep[y]];
    //        cout<<" ret before dele "<<ret<<endl;
            le=lower_bound(df[x].begin(),df[x].end(),po(L,-1))-df[x].begin();
            ri=upper_bound(df[x].begin(),df[x].end(),po(R,inf))-df[x].begin();
            if(le!=df[x].size()) ret-=df[x][le].bac,ret-=(ll)(df[x].size()-le)*dis[st][dep[y]];
            if(ri!=df[x].size()) ret+=df[x][ri].bac,ret+=(ll)(df[x].size()-ri)*dis[st][dep[y]];        
            x=fa[x];
        }
        return ret;
    }
    int main(){
        rd(n);rd(q);rd(A);
        for(reg i=1;i<=n;++i) rd(age[i]);
        int x,y,z;
        for(reg i=1;i<n;++i){
            rd(x);rd(y);rd(z);add(x,y,z);add(y,x,z);
        }
        nowsz=n;
        divi(1,1,0);
        ll ans=0;
        int a,b,L,R;
        while(q--){
            rd(x);rd(a);rd(b);
            L=min((a+ans)%A,(b+ans)%A),R=max((a+ans)%A,(b+ans)%A);
    //        cout<<" true "<<x<<" "<<L<<" "<<R<<endl;
            printf("%lld
    ",ans=wrk(x,L,R));
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/3/23 19:57:03
    */
    View Code

    法二:

    两个点距离怎么算?

    距离差分?

    考虑距离是怎么算的,∑dis+n*dis(x)-2*dis(lca)

    前面两个好算

    考虑每个点贡献作为lca应有的贡献,也就是经过的sz

    暴力跳不行,考虑树剖!

    考虑x头上的边贡献

    无[L,R]限制,直接把每个点到根的链上的sz++,

    有[L,R],主席树rt按照age,主席树的叶子下标是dfn序,权值是[1,i]颜色的fdfn[p]的子树的个数和

    加入一个点,重链跳,主席树标记永久化区间加

    查询时候,找一段链作为lca的贡献,就是主席树差分查区间和

    注意减去u子树的贡献

    一个点有时候携带多个信息

    一个区间的点的信息查询可以用主席树

    树链的点的信息查询,树剖+主席树!

  • 相关阅读:
    c语言排序算法
    冒泡 选择排序
    冒泡排序算法
    Pandas数据预处理
    Mongodb的安装和配置
    Mysql练习题
    5 根据过去的行为能否预测当下
    Sklearn逻辑回归
    4 如何通过各种广告组合获取更多的用户
    Sklearn多元线性回归
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10585755.html
Copyright © 2011-2022 走看看