題目描述
小c同學認為跑步非常有趣,於是決定制作一款叫做《天天愛跑步》的游戲。«天天愛跑步»是一個養成類游戲,需要玩家每天按時上線,完成打卡任務。
這個游戲的地圖可以看作一一棵包含 個結點和 條邊的樹, 每條邊連接兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從到的連續正整數。
現在有個玩家,第個玩家的起點為 ,終點為 。每天打卡任務開始時,所有玩家在第秒同時從自己的起點出發, 以每秒跑一條邊的速度, 不間斷地沿着最短路徑向着自己的終點跑去, 跑到終點后該玩家就算完成了打卡任務。 (由於地圖是一棵樹, 所以每個人的路徑是唯一的)
小C想知道游戲的活躍度, 所以在每個結點上都放置了一個觀察員。 在結點的觀察員會選擇在第秒觀察玩家, 一個玩家能被這個觀察員觀察到當且僅當該玩家在第秒也理到達了結點 。 小C想知道每個觀察員會觀察到多少人?
注意: 我們認為一個玩家到達自己的終點后該玩家就會結束游戲, 他不能等待一 段時間后再被觀察員觀察到。 即對於把結點作為終點的玩家: 若他在第秒重到達終點,則在結點的觀察員不能觀察到該玩家;若他正好在第秒到達終點,則在結點的觀察員可以觀察到這個玩家。
輸入輸出格式
輸入格式:
第一行有兩個整數和 。其中代表樹的結點數量, 同時也是觀察員的數量, 代表玩家的數量。
接下來 行每行兩個整數和 ,表示結點 到結點 有一條邊。
接下來一行 個整數,其中第個整數為 , 表示結點出現觀察員的時間。
接下來 行,每行兩個整數,和,表示一個玩家的起點和終點。
對於所有的數據,保證 。
輸出格式:
輸出1行 個整數,第個整數表示結點的觀察員可以觀察到多少人。
輸入輸出樣例
輸入樣例#1:
6 3
2 3
1 2
1 4
4 5
4 6
0 2 5 1 2 3
1 5
1 3
2 6
輸出樣例#1:
2 0 0 1 1 1
輸入樣例#2:
5 3
1 2
2 3
2 4
1 5
0 1 0 3 0
3 1
1 4
5 5
輸出樣例#2:
1 2 1 0 1
說明
【樣例1說明】
對於1號點,,故只有起點為1號點的玩家才會被觀察到,所以玩家1和玩家2被觀察到,共有2人被觀察到。
對於2號點,沒有玩家在第2秒時在此結點,共0人被觀察到。
對於3號點,沒有玩家在第5秒時在此結點,共0人被觀察到。
對於4號點,玩家1被觀察到,共1人被觀察到。
對於5號點,玩家1被觀察到,共1人被觀察到。
對於6號點,玩家3被觀察到,共1人被觀察到。
【子任務】
每個測試點的數據規模及特點如下表所示。 提示: 數據范圍的個位上的數字可以幫助判斷是哪一種數據類型。
【提示】
如果你的程序需要用到較大的棧空問 (這通常意味着需要較深層數的遞歸), 請務必仔細閱讀選手日錄下的文本當rumung:/stact.p″, 以了解在最終評測時棧空問的限制與在當前工作環境下調整棧空問限制的方法。
在最終評測時,調用棧占用的空間大小不會有單獨的限制,但在我們的工作
環境中默認會有 8 MB 的限制。 這可能會引起函數調用層數較多時, 程序發生
棧溢出崩潰。
我們可以使用一些方法修改調用棧的大小限制。 例如, 在終端中輸入下列命
令 ulimit -s 1048576
此命令的意義是,將調用棧的大小限制修改為 1 GB。
例如,在選手目錄建立如下 sample.cpp 或 sample.pas
將上述源代碼編譯為可執行文件 sample 后,可以在終端中運行如下命令運
行該程序
./sample
如果在沒有使用命令“ ulimit -s 1048576”的情況下運行該程序, sample
會因為棧溢出而崩潰; 如果使用了上述命令后運行該程序,該程序則不會崩潰。
特別地, 當你打開多個終端時, 它們並不會共享該命令, 你需要分別對它們
運行該命令。
請注意, 調用棧占用的空間會計入總空間占用中, 和程序其他部分占用的內
存共同受到內存限制。
思路
用lca算法,找到最近公共祖先,然后可以查出s到t的最短路徑(也可以用圖上最短路徑做法,但是畢竟這是在樹上,lca顯得更合適省時),於是可以找出路上每個點是在哪個時刻經過的,如果這個時刻與觀察員出現的時刻相同,則觀察員能觀察到的數量就+1
(郁悶ing,第一次打lca,幾乎用了一個上午的時間,卻因為超時只得了25分。。)
//怎么才能不超時!! #include<iostream> #include<vector> #include<cstring> #include<cstdio> using namespace std; vector<int>e[300000]; int dep[300000],f[300000][25]; int n,m,lca,num; int point[300000]; int ans[300000]; int cmp[300000]; int qread() { int x=0,j=1; char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')j=-1;ch=getchar();} while(ch<='9'&&ch>='0'){x=x*10+(int)(ch-'0');ch=getchar();} return x*j; } void find_deep(int pos,int pre) { for(int i=0;i<e[pos].size();i++) { if(e[pos][i]==pre)continue; else{ dep[e[pos][i]]=dep[pos]+1; f[e[pos][i]][0]=pos; find_deep(e[pos][i],pos); } } } void yuchuli() { for(int i=1;(1<<i)<=n;i++) { for(int j=1;j<=n;j++) { f[j][i]=f[f[j][i-1]][i-1]; } } } void show(int lca,int ed) { if(ed==lca)return; else show(lca,f[ed][0]); cmp[++num]=ed; } void dic(int start,int end) { bool flag=0;int a=start,b=end; if(dep[start]<dep[end])swap(a,b),flag=1; for(int i=20;i>=0;i--) if(dep[f[a][i]]>=dep[b]) a=f[a][i]; /*int t=dep[a]-dep[b]; for(int i=0;i<=20;i++){ if((1<<i)&t)a=f[a][i]; }*/ if(a==b) { lca=a; } else{ for(int i=20;i>=0;i--) if(f[a][i]!=f[b][i]) { a=f[a][i]; b=f[b][i]; } lca=f[a][0]; } int st,ed;st=start,ed=end; memset(cmp,0,sizeof(cmp)); num=0; cmp[++num]=st; while(st!=lca) { cmp[++num]=f[st][0]; st=f[st][0]; } show(lca,ed); //for(int i=1;i<=num;i++)cout<<cmp[i]<<' ';cout<<endl; for(int i=1;i<=num;i++) if(point[cmp[i]]==i-1)ans[cmp[i]]++; } int main() { n=qread();m=qread(); int from,to; for(int i=1;i<n;i++) { from=qread();to=qread(); e[from].push_back(to); e[to].push_back(from); } for(int i=1;i<=n;i++)cin>>point[i]; dep[1]=1; find_deep(1,-1); yuchuli(); //for(int i=1;i<=n;i++)cout<<dep[i]<<' ';cout<<endl; for(int i=1;i<=m;i++) { lca=0; int start,end; start=qread();end=qread(); dic(start,end); } for(int i=1;i<=n;i++) cout<<ans[i]<<' '; cout<<endl; }