1 条题解

  • 0
    @ 2025-8-24 23:04:13

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 是青白呀
    咕咕咕?咕咕咕!

    搬运于2025-08-24 23:04:13,当前版本为作者最后更新于2024-11-06 21:26:10,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    不难发现所有经过的管道会形成一个树形的结构,每一个询问实际上等价于求两点在树上的 LCA。于是考虑把树求出来之后跑 LCA 算法即可做到 O(n2)O(n^2),瓶颈在于树的点数是 O(n2)O(n^2) 级别的。

    不难发现很多点是无效的,于是考虑对这棵树建立虚树,只保留 n+1n+1 个叶子结点、nn 个既有左儿子、又有右儿子的分叉结点、以及 O(q)O(q) 个询问结点。

    首先对于每一层求出该层的分叉结点,可以通过使用树状数组维护路径经过点的横坐标的方式求出,每次需要的操作是后缀 1-1 和单点查询。

    然后考虑建树。我们从第 nn 层向第 00 层,由下往上扫描,维护当前层的每一个点在虚树上向下走遇到的(包含自己的)首个点的编号,需要支持的操作是的求第 kk 个点的点值、单点修改以及合并两个相邻点。这些操作可以用 FHQ 维护,但常数较大。我们亦可以用线段树维护,额外在叶子上维护一个标记 tagtag,其为 11 当且仅当这个点是某个合并形成的连续段的第一个点。此时求第 kk 个点的下标可以用线段树上二分实现。于是对于每一层,我们先求出要合并的两个点的标号,并新建一个节点作为它们虚树上的父亲;再遍历该层的所有询问点,对于每个点查询线段树上维护的、虚树上下方首个点,然后新建一个点作为其父亲即可。注意所有新建点的操作都要同时在线段树上进行单点修改。

    最后使用倍增、树剖、欧拉序等任意一种方式求 LCA 即可。总复杂度 O(nlogn)O(n\log n),代码较复杂,常数较大。

    #include<bits/stdc++.h>
    #define rep(i,j,k) for(int i=j;i<=k;i++)
    #define repp(i,j,k) for(int i=j;i>=k;i--)
    #define ls(x) (x<<1)
    #define rs(x) ((x<<1)|1)
    #define mp make_pair
    #define sec second
    #define fir first
    #define pii pair<int,int>
    #define lowbit(i) i&-i
    #define double long double
    #define qingbai 666
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int N=5e5+5,M=6,S=(1<<8)+5,inf=1e9+7,mo=1e9+7;
    const double eps=1e-8;
    void read(int &p){
    	int x=0,w=1;
    	char ch=0;
    	while(!isdigit(ch)){
    		if(ch=='-')w=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch)){
    		x=(x<<1)+(x<<3)+ch-'0';
    		ch=getchar();
    	}
    	p=x*w;
    }
    int n,a[N],m,cntp,qid[N][2],bel[N*2];
    pii q[N][2],p[N*2];
    int cntn=0;
    int pt[N];
    struct BIT{
        int t[N];
        void add(int x,int v){
            for(int i=x;i<=n;i+=lowbit(i))
                t[i]+=v;
        }
        int query(int x){
            int res=0;
            for(int i=x;i;i-=lowbit(i))
                res+=t[i];
            return res;
        }
    }BIT;
    vector<pii>targp[N];
    vector<int>e[N*4];
    struct seg{
        int t[4*N],sum[4*N];
        void pushup(int x){
            sum[x]=sum[ls(x)]+sum[rs(x)];
        }
        void modifyn(int x,int le,int ri,int p,int v){
            if(le==ri){
                t[x]=v;
                return;
            }
            int mid=(le+ri)>>1;
            if(p<=mid)modifyn(ls(x),le,mid,p,v);
            else modifyn(rs(x),mid+1,ri,p,v);
        }
        void modifys(int x,int le,int ri,int p,int v){
            if(le==ri){
                sum[x]=v;
                return;
            }
            int mid=(le+ri)>>1;
            if(p<=mid)modifys(ls(x),le,mid,p,v);
            else modifys(rs(x),mid+1,ri,p,v);
            pushup(x);
        }
        int queryp(int x,int le,int ri,int v,int op){
            if(le==ri){
                if(op)bel[op]=cntn,e[cntn].push_back(t[x]),t[x]=cntn;
                return le;
            }
            int mid=(le+ri)>>1;
            if(sum[ls(x)]>=v)return queryp(ls(x),le,mid,v,op);
            else return queryp(rs(x),mid+1,ri,v-sum[ls(x)],op);
        }
        int queryn(int x,int le,int ri,int p){
            if(le==ri)return t[x];
            int mid=(le+ri)>>1;
            if(p<=mid)return queryn(ls(x),le,mid,p);
            else return queryn(rs(x),mid+1,ri,p);
        }
    }T;
    int fa[N*4][20],dep[N*4];
    pii ttp[N*4];
    void dfs(int x,int f){
        dep[x]=dep[f]+1;
        fa[x][0]=f;
        rep(i,1,19)
            fa[x][i]=fa[fa[x][i-1]][i-1];
        for(auto j:e[x])
            dfs(j,x);
    }
    int lca(int x,int y){
        if(dep[x]<dep[y])swap(x,y);
        repp(i,19,0)
            if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
        if(x==y)return x;
        repp(i,19,0)
            if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    signed main(){
        read(n);
        rep(i,1,n)
            read(a[i]),BIT.add(i,1);
        rep(i,1,n){
            pt[a[i]]=BIT.query(a[i]);
            BIT.add(a[i]+1,-1);
        }
        read(m);
        rep(i,1,m){
            read(q[i][0].fir),read(q[i][0].sec),read(q[i][1].fir),read(q[i][1].sec);
            if(q[i][0]>q[i][1])swap(q[i][0],q[i][1]);
            q[i][0].fir++,q[i][0].sec++,q[i][1].fir++,q[i][1].sec++;
            p[++cntp]=q[i][0],p[++cntp]=q[i][1];
        }
        sort(p+1,p+cntp+1),cntp=unique(p+1,p+cntp+1)-p-1;
        rep(i,1,m){
            qid[i][0]=lower_bound(p+1,p+cntp+1,q[i][0])-p;
            qid[i][1]=lower_bound(p+1,p+cntp+1,q[i][1])-p;
        }
        rep(i,1,cntp)
            targp[p[i].fir].push_back(mp(p[i].sec,i));
        rep(i,1,n+1){
            cntn++,ttp[i]=mp(n+1,i);
            T.modifyn(1,1,n+1,i,cntn);
            T.modifys(1,1,n+1,i,1);
        }
        for(auto j:targp[n+1])
            bel[j.sec]=j.fir;
        repp(i,n,1){
            int targ=T.queryp(1,1,n+1,pt[i],0),nxtt=T.queryp(1,1,n+1,pt[i]+1,0);
            int x=T.queryn(1,1,n+1,targ),y=T.queryn(1,1,n+1,nxtt);
            T.modifys(1,1,n+1,nxtt,0);
            cntn++,ttp[cntn]=mp(i,pt[i]);
            e[cntn].push_back(x),e[cntn].push_back(y);
            T.modifyn(1,1,n+1,targ,cntn);
            int nid=cntn;
            for(auto j:targp[i]){
                if(j.fir==pt[i])bel[j.sec]=nid;
                else cntn++,ttp[cntn]=mp(i,j.fir),T.queryp(1,1,n+1,j.fir,j.sec);
            }
        }
        dfs(cntn,0);
        rep(i,1,m){
            int lcap=lca(bel[qid[i][0]],bel[qid[i][1]]);
            printf("%d %d\n",ttp[lcap].fir-1,ttp[lcap].sec-1);
        }
        return 0;
    }
    
    • 1

    信息

    ID
    8983
    时间
    2000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者