hdu 4916 Count on the path

给定一棵 \(n\) 个节点的树和 \(m\) 个询问,每个询问要求回答不在 \(u\)\(v\) 两节点所形成的路径上的点的最小标号。要求强制在线 .

\(1\leq n,q\leq 10^6\)

首先,根节点就是 \(0\) 号节点 .

如果 \(u\)\(v\) 的路径不经过 \(0\) 号节点,那么,答案就是 \(0\) .

那么,\(u\)\(v\) 必定是 \(0\) 号节点同一个子树中的点 .

否则,如果 \(u\)\(v\) 经过了根节点,即 \(0\) 号节点 .

那么,路径必定是 \(0\rightarrow u\)\(0\rightarrow v\) 拼在一起的 . 那么,\(u\)\(v\) 处在不同的子树 .

答案的构成是 \(u\) 所在子树中 \(0\rightarrow u\) 之外的点的最小编号 + \(v\) 所在子树中 \(0\rightarrow v\) 之外的点的最小编号 + 除了 \(u,v\) 所在子树以外所有 \(0\) 的子树中的最小编号 .

那么 \(u\) 所在子树中 \(0\rightarrow u\) 之外的点的最小编号和 \(v\) 所在子树中 \(0\rightarrow v\) 之外的点的最小编号可以预处理出来,用 \(dp(x)\) 表示 .

但是,如何 \(O(1)\) 地求出除了 \(u,v\) 所在子树以外所有 \(0\) 的子树中的最小编号呢?

可以先求出每个子树中的最小编号,保留前三小的最小编号 . 枚举前三小,必定有一棵树不是 \(u,v\) 所在的子树,那么,这些子树的最小编号就是上述值 .

因此,就是可以每次询问 \(O(1)\) 地求出最小值 .

这个题目在 hdu 上我提交了死活过不去 QwQ,手写了链接表和换做 bfs ,又加上了长长的优化之后都不可以. 但是,这个代码在学校的网站上却跑到了最快,737ms ,嘿嘿 .

时间复杂度 : \(O(n+m)\)

空间复杂度 : \(O(n)\)

第一次提交 : Time Limited Exceed

#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("Ofast")
#pragma GCC optimize(3)
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,tune=native")
#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘)ch=getchar();
    int res=0;
    while(ch>=‘0‘&&ch<=‘9‘){
        res=res*10+ch-‘0‘;
        ch=getchar();
    }
    return res;
}
inline void print(int res){
    int a[8];
    int len=0;
    while(res>0){
        a[len++]=res%10;
        res/=10;
    }
    for(int i=len-1;i>=0;i--)putchar(‘0‘+a[i]);
    putchar(‘\n‘);
}
const int inf=1e9+10;
int n,q;
int head[1000010],nxt[2000010],to[2000010],cnt=0;
int id[1000010],dp[1000010],mn[1000010],mn2[1000010];
int fa[1000010];
int st=0,ed=0;
int Q[1000010];
int len=0;
int a[1000010];
int main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    for(int i=0;i<1000010;i++)id[i]=head[i]=-1,dp[i]=mn[i]=mn2[i]=inf;
    while(~scanf("%d%d",&n,&q)){
        for(int i=0;i<n-1;i++){
            int u=read()-1,v=read()-1;
            nxt[cnt]=head[u];to[cnt]=v;head[u]=cnt++;
            nxt[cnt]=head[v];to[cnt]=u;head[v]=cnt++;
        }
        for(int i=head[0];i!=-1;i=nxt[i]){
            st=ed=len=0;
            Q[ed++]=to[i];fa[to[i]]=0;
            while(st<ed){
                int x=Q[st++];id[x]=to[i];a[len++]=x;
                for(int j=head[x];j!=-1;j=nxt[j]){
                    if(to[j]!=fa[x]){
                        fa[to[j]]=x;
                        Q[ed++]=to[j];
                    }
                }
            }
            for(int j=len-1;j>=0;j--){
                mn[a[j]]=min(mn[a[j]],a[j]);
                if(fa[a[j]]!=0)mn[fa[a[j]]]=min(mn[fa[a[j]]],mn[a[j]]);
            }
            st=ed=0;
            Q[ed++]=to[i];
            while(st<ed){
                int x=Q[st++];
                int tmp=inf;len=0;
                dp[x]=mn2[x];
                for(int j=head[x];j!=-1;j=nxt[j]){
                    if(to[j]!=fa[x]){
                        mn2[to[j]]=min(mn2[x],tmp);
                        tmp=min(tmp,mn[to[j]]);
                        a[len++]=to[j];
                    }
                }
                tmp=inf;
                for(int j=len-1;j>=0;j--){
                    dp[x]=min(dp[x],mn[a[j]]);
                    mn2[a[j]]=min(mn2[a[j]],tmp);
                    tmp=min(tmp,mn[a[j]]);
                }
                for(int j=0;j<len;j++)Q[ed++]=a[j];
            }
         
        }
    //  for(int i=0;i<n;i++)cout<<id[i]<<" ";cout<<endl;
    //  for(int i=0;i<n;i++)cout<<mn[i]<<" ";cout<<endl;
    //  for(int i=0;i<n;i++)cout<<mn2[i]<<" ";cout<<endl;
    //  for(int i=0;i<n;i++)cout<<dp[i]<<" ";cout<<endl;
        int num[4]={-1,-1,-1,-1};
        for(int i=head[0];i!=-1;i=nxt[i]){
            num[3]=to[i];
            for(int j=2;j>=0;j--){
                if(num[j]==-1||mn[num[j+1]]<mn[num[j]])
                    swap(num[j+1],num[j]);
            }
        }
    //  for(int i=0;i<3;i++)cout<<num[i]<<" ";cout<<endl;
        int ans=0;
        for(int t=0;t<q;t++){
            int u=read()^ans,v=read()^ans;
            u--;v--;
        //  cout<<u<<" "<<v<<": "<<id[u]<<" "<<id[v]<<endl;
            ans=inf;
            if(u==0||v==0){
                if(u==v)ans=1;
                else{
                    if(u!=0)swap(u,v);
                    ans=dp[v];
                    for(int i=0;i<3;i++){
                        if(num[i]!=id[v]&&num[i]!=-1){
                            ans=min(ans,mn[num[i]]);
                        }
                    }
                }   
            }
            else if(id[u]==id[v])ans=0;
            else{
                ans=min(dp[u],dp[v]);               
                for(int i=0;i<3;i++){
                    if(num[i]!=id[u]&&num[i]!=id[v]&&num[i]!=-1)
                        ans=min(ans,mn[num[i]]);
                }
            }
            ans++;
            print(ans);
        }
        for(int i=0;i<n;i++)dp[i]=mn[i]=mn2[i]=inf,id[i]=head[i]=-1;
        cnt=0;
    }
    return 0;
}
/*inline? ll or int? size? min max?*/

hdu 4916 Count on the path

上一篇:第 36 题:什么是原型、原型链、继承?


下一篇:Date对象获取统计时间:上月、本季度、上季度、今年