• 「JOISC 2020 Day3」收获


    「JOISC 2020 Day3」收获

    分类讨论.jpg

    分析一棵苹果树被不断摘掉的过程,找到第一个摘它的人(i)

    此后,每次摘它的人,就是(i)前面第一个距离它(ge C)的人,不妨设其为(nxt_i)

    显然,(i,nxt_i)的关系,会构成基环内向树森林,每条内向边有一个权值(w_i)

    容易(O(n))尺取得到(nxt_i,w_i),考虑选择环上的一个点(u),断开(u)对应的内向边,得到一棵树

    Snipaste_2021-03-13_13-26-19.png

    处理得到环长(len_u),令(dis_u=w_u),树上每个点的(dis_v=dis_{nxt_v}+w_v)

    考虑一棵苹果树被第一次摘的情况,用一个二元组表示((v,t)),即被(v)(t)时刻摘掉

    我们认为是苹果树在基环内向树上走

    1.苹果树不跨过(u)时的贡献

    此时相当于每个((v,t))在往根节点走,贡献来自每个查询((x,d))的子树

    即满足(vin subtree_x,dis_v-dis_x+tleq d)

    离散之后可以用简单的 询问离线+(dfs)作差+树状数组解决

    [ ]

    2.跨过(u),先将苹果树的贡献移动到(last)上,变为((last,t'=t+dis_v))

    对于每个询问,显然必须满足(x)在环上

    我们也可以令(d'=d-(len_u-dis_v)),同样将(x)移动到(last)

    此时只需要考虑每个(t')对于(d')的贡献

    按照(len_u),我们可以将(t',d')分段,每段都是([icdot len_u,(i+1)cdot len_u))的形式

    2-1.对于不是同一段内的,每个(t')的对于(d')的贡献次数 就是 段编号 之差

    2-2.同一段内,就是满足(t'leq d')(t'mod len_uleq d'mod len_u) 的个数

    将所有(d',t')排序后依次处理,容易通过参数分离处理2-1

    对于2-2,将(t'mod len_u)离散后可以用树状数组处理

    Loj Submission

    空间复杂度为(O(n)),时间复杂度为(O(nlog n))

    #include<bits/stdc++.h>
    using namespace std;
    using ll=int64_t;
    #define pb push_back
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    ll rd(){
        char c;ll s=0;
        while(c=getchar(),c<48);
        do s=(s<<1)+(s<<3)+(c^'0');
        while(c=getchar(),c>47);
        return s;
    }
    enum{N=200010};
    int n,m,q,nxt[N],L,C,C2,A[N*2],B[N],id[N],incir[N];
    vector <int> E[N],G[N];
    ll H[N],dis[N],H2[N],len[N],ans[N];
    void dfs(int u){
        for(int i:E[u]) H[++C]=dis[u]+i;
        vector <int> tmp;
        for(int v:G[u]) {
            if(id[v]==id[u]) continue;
            tmp.pb(v),id[v]=id[u];
            dis[v]+=dis[u],dfs(v);
        }
        G[u]=tmp;
    }
    
    struct Node{ ll d; int id; };
    vector <Node> Q[N],que;
    vector <ll> upd;
    struct BIT{
        int s[N],n;
        void Init(int m){ n=m,memset(s,0,(n+1)<<2); }
        void Add(int p,int x) { while(p<=n) s[p]+=x,p+=p&-p; }
        int Que(int p) {
            int res=0;
            while(p) res+=s[p],p-=p&-p;
            return res;
        }
    } T,X;
    
    // dfs作差处理情况1
    void dfs2(int u){
        for(Node &i:Q[u]) {
            // 如果满足查询点在环上,就要加入2-1,2-2的计算
            if(incir[u]) {
                ll d=i.d-(len[id[u]]-dis[u]);
                if(d>=0) que.pb((Node){d,i.id});
            }
            // dfs作差-1
            ans[i.id]-=T.Que(i.d=upper_bound(H+1,H+C+1,dis[u]+i.d)-H-1);
        }
        for(int i:E[u]) T.Add(lower_bound(H+1,H+C+1,dis[u]+i)-H,1),upd.pb(dis[u]+i);
        for(int v:G[u]) dfs2(v);
        // dfs作差+1
        for(Node i:Q[u]) ans[i.id]+=T.Que(i.d);
    }
    
    int main(){
        n=rd(),m=rd(),L=rd(),C=rd();
        rep(i,0,n-1) A[i]=rd(),A[i+n]=A[i]+L;
        rep(i,0,m-1) B[i]=rd();
        int C_=C%L,p=0;
        // 尺取预处理i,nxt[i],w[i]
        rep(i,n,n*2-1) {
            while(p<i && A[i]-A[p+1]>=C_) p++;
            nxt[i-n]=p%n,G[p%n].pb(i-n);
            dis[i-n]=C-C_+A[i]-A[p];
        }
        p=0;
        // 预处理(v,t)
        rep(i,0,m-1) {
            while(p<n*2-1 && B[i]+L>=A[p+1]) p++;
            E[p%n].pb(B[i]+L-A[p]);
        }
        C=0;
        // 断环构建树
        rep(i,0,n-1) id[i]=-2;
        rep(i,0,n-1) if(id[i]==-2) {
            int u=i;
            for(;~id[u];u=nxt[u]) id[u]=-1;
            id[u]=u,len[u]=dis[u],incir[u]=1;
            for(int v=nxt[u];v!=u;v=nxt[v]) len[u]+=dis[v],incir[v]=1;
            dfs(u);
        }
        sort(H+1,H+C+1),T.Init(C=unique(H+1,H+C+1)-H-1);
        // 离线询问,权值离散
        rep(i,1,q=rd()) {
            int u=rd()-1; ll d=rd();
            Q[u].pb((Node){d,i});
        }
        rep(i,0,n-1) if(id[i]==i) {
            que.clear(),upd.clear();
            dfs2(i);
            sort(upd.begin(),upd.end()),sort(que.begin(),que.end(),[&](Node x,Node y){ return x.d<y.d; });
            C2=0;
            for(ll x:upd) H2[++C2]=x%len[i];
            sort(H2+1,H2+C2+1),X.Init(C2=unique(H2+1,H2+C2+1)-H2-1);
            auto it=upd.begin();
            ll s=0,c=0;
            for(Node &q:que) {
                while(it!=upd.end() && *it<=q.d) 
                    X.Add(lower_bound(H2+1,H2+C2+1,*it%len[i])-H2,1),s+=*(it++)/len[i],c++;
                // 参数分离处理2-1
                ans[q.id]+=q.d/len[i]*c-s;
                // 树状数组查询2-2
                ans[q.id]+=X.Que(upper_bound(H2+1,H2+C2+1,q.d%len[i])-H2-1);
            }
        }
        rep(i,1,q) printf("%lld
    ",ans[i]);
    }
    
    
  • 相关阅读:
    java Set(集合)
    java Stack(栈)
    java LinkedList(链表)
    简单的maven配置
    Linux下如何查找.sh后缀的文件
    linux 下shell中if的“-e,-d,-f”是什么意思
    linux重定向
    shell中$0,$?,$!等的特殊用法
    向shell脚本中传入参数
    mysql索引
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14528472.html
Copyright © 2020-2023  润新知