NOIP-模拟试题之--避难向导

2018 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(Si>=qi)。如果存在这样的城市(包含xi和yi),则输出城市编号,否则输出一行包括一个数-1。
【输入格式】
从文件shelter.in中读入数据。
输入的第1行包含5个数:依次是n, m, a, b, c。接下来n-1行描述公路的信息,每行3个数,前两个数代表这条公路连接的两个城市的编号,第三个数表示这条公路的长度(在32位整数范围以内)。再接下来m行,每行描述一个询问,包含三个数xi, yi和qi。
【输出格式】
输出到文件shelter.out中。
对于每个询问,输出一行包含一个整数,存在符合要求的城市则输出城市编号,不存在则输出-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

【数据规模与约定】
。。。,N<=100000,M<=300000

——————————————————————————————————————————————————

。。。没什么难度的样子。
考虑一下封闭系数的问题,显然跟直径有关,离树上一个点最远的叶子结点显然就是由叶子结点为端点构成的最长链的端点其中之一(不然找到的就不是最长链),然后安全系数的问题就解决了。
考虑询问,询问里面要求找离起点最近的那个点使得Si>=p,那么就用二分,把询问的路径拆成向上和向下的,看向上路径的里面有没有一个点的S>=p,有的话就在向上里面来猜,没有的话就在向下里面猜。当然移动的时候肯定要用倍增,虽然看起来是一个logN*logN的复杂度,但是可以发现每一次都是“验证当前->变成一半的模式”,就类似于1+1/2+1/4……最后无限逼近于2的感觉,由于有一个验证当前有没有解的过程所以大不了乘个3(一半只会少爬一次),回答一次询问的时间复杂度变成O(6logN),不会超时。
分析一堆,总时间复杂度为O(NlogN+(6)MlogN)。(PS:S写成了D不要在意AuA)

AC代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=100005;
typedef long long LL;

int N,M,a,b,c;
struct edge{ int to,next,w; }E[maxn<<1];
int first[maxn],np,dep[maxn],fa[maxn][18];
int o1,o2,D[maxn],du[maxn],maxd[maxn][18];
LL d1[maxn],d2[maxn],dist[maxn];

void _scanf(int &x)
{
x=0;
char ch=getchar();
while(ch<‘0’||ch>‘9’) ch=getchar();
while(ch>=‘0’&&ch<=‘9’) x=x*10+ch-‘0’,ch=getchar();
}
void add_edge(int u,int v,int w)
{
E[++np]=(edge){v,first[u],w};
first[u]=np;
}
void data_in()
{
_scanf(N);_scanf(M);_scanf(a);_scanf(b);_scanf©;
int x,y,z;
for(int i=1;i<N;i++)
{
_scanf(x);_scanf(y);_scanf(z);
du[x]++;du[y]++;
add_edge(x,y,z);
add_edge(y,x,z);
}
}
void getd(int i,int f,LL l,int &o)
{
dist[i]=l;
if(du[i]1&&dist[i]>dist[o]) o=i;
for(int p=first[i];p;p=E[p].next)
{
int j=E[p].to;
if(j
f) continue;
getd(j,i,l+E[p].w,o);
}
}
void DFS(int i,int f,LL l,LL *d)
{
d[i]=l;
for(int p=first[i];p;p=E[p].next)
{
int j=E[p].to;
if(jf) continue;
DFS(j,i,l+E[p].w,d);
}
}
void _DFS(int i,int f,int d)
{
dep[i]=d;
fa[i][0]=f;
maxd[i][0]=max(D[i],D[f]);
for(int j=1;(1<<j)<d;j++)
{
fa[i][j]=fa[fa[i][j-1]][j-1];
maxd[i][j]=max(maxd[i][j-1],maxd[fa[i][j-1]][j-1]);
}
for(int p=first[i];p;p=E[p].next)
{
int j=E[p].to;
if(j
f) continue;
_DFS(j,i,d+1);
}
}
int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
int len=dep[x]-dep[y];
for(int j=0;(1<<j)<=len;j++)
if((1<<j)&len) x=fa[x][j];
if(x==y) return x;
for(int j=17;j>=0;j–)
if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
return fa[x][0];
}
int solve1(int x,int y,int p)
{
if(dep[x]-dep[y]<=1)
{
if(D[x]>=p) return x;
if(D[y]>=p) return y;
return -1;
}
int len=dep[x]-dep[y],maxv=0;
int z=x;
for(int j=0;(1<<j)<=len;j++)
if((1<<j)&len) maxv=max(maxv,maxd[z][j]),z=fa[z][j];
if(maxv<p) return -1;
len/=2;
z=x;
for(int j=0;(1<<j)<=len;j++)
if((1<<j)&len) z=fa[z][j];
int re=solve1(x,z,p);
if(re!=-1) return re;
return solve1(fa[z][0],y,p);
}
int solve2(int x,int y,int p)
{
if(dep[x]-dep[y]<=1)
{
if(D[y]>=p) return y;
if(D[x]>=p) return x;
return -1;
}
int len=dep[x]-dep[y],maxv=0;
int z=x;
for(int j=0;(1<<j)<=len;j++)
if((1<<j)&len) maxv=max(maxv,maxd[z][j]),z=fa[z][j];
if(maxv<p) return -1;
len/=2;
z=x;
for(int j=0;(1<<j)<=len;j++)
if((1<<j)&len) z=fa[z][j];
int re=solve2(fa[z][0],y,p);
if(re!=-1) return re;
return solve2(x,z,p);
}
void work()
{
for(int i=1;i<=N;i++)
if(du[i]==1) { o1=i; break; }
getd(o1,0,0,o1);
getd(o1,0,0,o2=o1);
DFS(o1,0,0,d1);
DFS(o2,0,0,d2);
for(int i=1;i<=N;i++)
D[i]=(max(d1[i],d2[i])+a)*b%c;
_DFS(1,0,1);

int x,y,ans,gf,p;
for(int i=1;i<=M;i++)
{
    _scanf(x);_scanf(y);_scanf(p);
    gf=LCA(x,y);
    ans=solve1(x,gf,p);
    if(ans==-1) ans=solve2(y,gf,p);
    printf("%d\n",ans);
}

}
int main()
{
freopen(“shelter.in”,“r”,stdin);
freopen(“shelter.out”,“w”,stdout);
data_in();
work();
return 0;
}


原文:https://blog.csdn.net/qq_39439314/article/details/78165634

猜你喜欢

转载自blog.csdn.net/tianli315/article/details/84942182