1. 程式人生 > >NOIP-模擬試題之--避難嚮導

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