zoukankan      html  css  js  c++  java
  • CQBZOJ 【重庆市NOIP模拟赛】避难向导

    题目描述
    “特大新闻,特大新闻!全国爆发了一种极其可怕的病毒,已经开始在各个城市 中传播开来!全国陷入了巨大的危机!大量居民陷入恐慌,想要逃到其它城市以 避难!经调查显示,该病毒来自于C 市的A 学校的一次非法的……” “哎。”你关上电视,叹了口气。作为A 学校的校长,你一天前为了保命,独自 逃离了A 学校,抛弃了全校师生,包括那个曾经帮你计算并拆除道路的工程师。 你良心受到了巨大的谴责,因此决定做出一些补救,回答一些逃难的人提出的询 问。 已知该国一共有n 个城市,并且1 号城市是首都。(n-1)条双向的公路连接这些 城市,通过这些公路,任意两个城市之间存在且仅存在一条路径。每条公路有一 个长度。如果一个城市只与一条公路相连,则称它为边境城市。 该国政府有一个奇怪的规定:每个城市有一个封闭系数di,定义di 为离这个城 市最远的边境城市到这个城市的距离。市民们认为,一个城市的安全系数Si 和 它的封闭系数有很重要的联系。a,b,c 是该国的幸运数字,所以大家公认一个 城市的安全系数Si = (di + a) * b mod c。 市民们一共会提出m 次询问。每个询问包含三个信息,xi,yi 和qi。xi 是询问 者所在的城市编号。你要为这个询问者在xi 到yi 的必经之路上找出一个离xi 最近的避难城市,并且要求这个避难城市的安全系数大于等于qi。如果存在这 样的城市(包含xi 和yi),则输出城市编号,否则输出一行包括一个数-1。

    输入
    第一行五个数:依次是n, m, a, b, c。 接下来n-1 行描述公路的信息。每行三个数,前两个数代表这条公路连接的两个 城市的编号,第三个数表示这条公路的长度。 再接下来m 行,每行描述一个询问,包含三个数xi, yi 和qi。

    输出
    对于每个询问,输出一行包含一个整数,存在符合要求的城市则输出城市编号, 不存在则输出-1。

    样例输入

    7 6 5 6 20
    1 2 4
    2 4 2
    2 5 3
    1 3 5
    3 6 6
    6 7 7
    7 5 15
    3 4 5
    5 4 2
    4 5 2
    6 6 10
    3 5 19
    样例输出
    6
    3
    2
    4
    6
    -1

    这个题目本身就是两种题型的合并
    1、树的最长路径
    2、树形倍增数组寻找最值

    m^2p 刚学倍增就做这种有(wei)趣(suo)的题真的好吗

    先解决最长链的问题,我用的是DP做法,时间复杂度为O(n)
    g[root][0]g[root][1]为以root为根节点的子树由树根到叶节点的最长链和次长链,注意,最长链与次长链无重合边
    一次DFS即可初始化

    再设f[root][0]f[root][1]表示以root为起点的最长链和次长链,也无重合边,一次DFS也可做到

    最麻烦的就是倍增查询了:
    先看看m的范围 300000
    300000 是一个转折点,因为O(nlognlogn)300000下会TLE
    这就让我们只能用O(nlogn)来解决问题

    状态应该不难定义:
    f[i][j]表示i节点的第2j个祖先的节点编号
    g[i][j]表示i节点到第2j个祖先之间的点权最大值

    接下来便是O(logn)的查询,O(longnlogn)很好想,但现实就是这么骨感QwQ

    c=LCA(a,b),将一个路径拆分成a>c>b两部分

    将总任务拆分成两个子任务

    将一条xy的直链看成A和B两部分
    A中包含2的整数次幂个节点,且A的长度大于xy总长度的一半
    通过这样的观点来考察上述两个子任务:

    这里写图片描述

    一、离x最近的:
    知道k时,可以O(1)判断答案是否在A中。
    ① 如果在A中,枚举ik10即可得到答案。
    ② 如果A中不存在合法解,则令x=f[x][k],递归进行以上过程。
    对于①,整个递归过程中只有得出答案前会被执行一次。
    对于②,每次递归后k的值减少,而k上界为logn,下界为0,所以递归深度为O(logn)
    综上,该操作复杂度为O(logn)

    二、离x最远的:
    ① 优先令x=f[x][k],递归在B段中求解。如递归返回后已经得到答案,则直接返回答案。
    ② 如经过①没有获得答案,则O(1)检查A段中是否有答案,如果没有,则xy整段路径中无解。如果有,则枚举ik10即可定位答案。
    类似子任务一,该部分的复杂度为O(logn)

    码了三个小时,终于AC了!!!!!!

    代码如下:

    #include<cstdio> 
    #include<cmath> 
    #include<cstring> 
    #include<algorithm> 
    
    #define LOG 20 
    #define maxn 100000 
    
    using namespace std; 
    
    inline int getint() 
    { 
        int num=0,flag=1;char c; 
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1; 
        while(c>='0'&&c<='9')num=num*10+c-48,c=getchar(); 
        return num*flag; 
    } 
    
    int s[maxn+5]; 
    int fir[2*maxn+5],nxt[2*maxn+5],to[2*maxn+5],dis[2*maxn+5],cnt; 
    int n,m,a,b,c; 
    
    inline void newnote(int u,int v,int w){to[++cnt]=v,dis[cnt]=w,nxt[cnt]=fir[u],fir[u]=cnt;} 
    
    struct node1{ 
    
        int f[maxn+5][2],g[maxn+5][2]; 
        bool vis[maxn+5]; 
    
        inline void work(int root) 
        { 
            int i; 
            vis[root]=1; 
            for(i=fir[root];i;i=nxt[i]) if(!vis[to[i]]) 
            { 
                work(to[i]); 
                if(g[to[i]][0]+dis[i]>g[root][0])
                    g[root][1]=g[root][0],g[root][0]=g[to[i]][0]+dis[i]; 
                else if(g[to[i]][0]+dis[i]>g[root][1])
                    g[root][1]=g[to[i]][0]+dis[i]; 
            } 
        } 
    
        inline void dp(int x,int fa,int c) 
        { 
            vis[x]=1; 
            if(x==1) 
                f[x][0]=g[x][0],f[x][1]=g[x][1]; 
            else if(f[fa][0]==g[x][0]+c) 
            { 
                if(g[x][0]>=f[fa][1]+c)
                    f[x][0]=g[x][0],f[x][1]=max(f[fa][1]+c,g[x][1]); 
                else 
                    f[x][0]=f[fa][1]+c,f[x][1]=g[x][0]; 
            } 
            else
                f[x][0]=f[fa][0]+c,f[x][1]=g[x][0]; 
            for(int i=fir[x];i;i=nxt[i])
                if(!vis[to[i]])dp(to[i],x,dis[i]); 
        } 
    
    }farthest; 
    
    struct node2{ 
    
        int f[maxn+5][LOG+1],g[maxn+5][LOG+1],dep[maxn+5]; 
        bool vis[maxn+5]; 
    
        inline void dfs(int x) 
        { 
            for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]) 
            { 
                vis[to[i]]=1;dep[to[i]]=dep[x]+1;f[to[i]][0]=x; 
                g[to[i]][0]=max(s[to[i]],s[x]);dfs(to[i]); 
            } 
        } 
    
        inline void dp() 
        { 
            for(int j=1;j<=LOG;j++)for(int i=1;i<=n;i++) 
            { 
                f[i][j]=f[f[i][j-1]][j-1]; 
                g[i][j]=max(g[f[i][j-1]][j-1],g[i][j-1]); 
            } 
        } 
    
        inline int getg(int u,int k) 
        { 
            int ans=-(1<<30); 
            for(int i=LOG;i>=0;i--) 
                if(k&(1<<i))ans=max(ans,g[u][i]),u=f[u][i]; 
            return ans; 
        } 
    
        inline int getk(int u,int k) 
        { 
            for(int i=LOG;i>=0;i--) 
                if(k&(1<<i))u=f[u][i]; 
            return u; 
        } 
    
        inline int getd(int u,int d){return getk(u,dep[u]-d);} 
    
        inline int LCA(int u,int v) 
        { 
            int x=getd(u,min(dep[v],dep[u]));
            int y=getd(v,min(dep[u],dep[v])); 
            if(x==y)return x; 
            for(int i=LOG;i>=0;i--) 
                if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; 
            return f[x][0]; 
        } 
    
        inline int getg1(int x,int y,int w) 
        { 
            if(x==y)return s[x]>=w?x:-1; 
            int t=log2(dep[x]-dep[y]); 
            if(g[x][t]>=w) 
            { 
                for(int i=t-1;i>=0;i--) 
                    if(g[x][i]<w)x=f[x][i]; 
                return s[x]>=w?x:f[x][0]; 
            } 
            else return getg1(f[x][t],y,w); 
        } 
    
        inline int getg2(int x,int y,int w) 
        { 
            if(x==y)return s[x]>=w?x:-1; 
            int t=log2(dep[x]-dep[y]); 
            int tmp=getg2(f[x][t],y,w); 
            if(tmp!=-1) return tmp; 
            if(g[x][t]>=w) 
            { 
                for(int i=t-1;i>=0;i--) 
                    if(g[f[x][i]][i]>=w)x=f[x][i]; 
                return s[f[x][0]]>=w?f[x][0]:x;
            } 
            return -1; 
        } 
    
    }getans; 
    
    int main() 
    { 
        int i,u,v,w; 
        n=getint(),m=getint(),a=getint(),b=getint(),c=getint(); 
        for(i=1;i<n;i++) 
        { 
            u=getint(),v=getint(),w=getint(); 
            newnote(u,v,w),newnote(v,u,w); 
        } 
        farthest.work(1);
        memset(farthest.vis,0,sizeof farthest.vis);
        farthest.dp(1,0,0); 
        for(i=1;i<=n;i++)
            s[i]=((long long)((farthest.f[i][0]+a)%c)*(b%c))%c; 
        getans.dep[1]=getans.vis[1]=1,getans.dfs(1); 
        getans.dp(); 
        for(i=1;i<=m;i++) 
        { 
            u=getint(),v=getint(),w=getint(); 
            if(u==v){printf("%d
    ",s[u]<w?-1:u);continue;} 
            int lca=getans.LCA(u,v);
            int g1=getans.getg1(u,lca,w),g2=getans.getg2(v,lca,w); 
            if(~g1)printf("%d
    ",g1); 
            else printf("%d
    ",g2); 
        } 
    } 
  • 相关阅读:
    C#窗体操作的小技巧
    C#操作Xml
    Path类对路径字符串的操作
    Google Maps 基础
    C#时间操作总结
    根据地理坐标计算瓦片行列号
    使用VBA宏批量修改表格
    检测到在集成的托管管道模式下不适用的ASP.NET设置的解决方法
    Asp.net实现URL重写
    VS2013利用ajax访问不了json文件——VS2013配置webconfig识别json文件
  • 原文地址:https://www.cnblogs.com/Darknesses/p/12002543.html
Copyright © 2011-2022 走看看