日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HDU4812-D Tree-树分治

發布時間:2023/11/30 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU4812-D Tree-树分治 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

There is a skyscraping tree standing on the playground of Nanjing University of Science and Technology. On each branch of the tree is an integer (The tree can be treated as a connected graph with N vertices, while each branch can be treated as a vertex). Today the students under the tree are considering a problem: Can we find such a chain on the tree so that the multiplication of all integers on the chain (mod 10 6 + 3) equals to K?
Can you help them in solving this problem?
Input
There are several test cases, please process till EOF.
Each test case starts with a line containing two integers N(1 <= N <= 10 5) and K(0 <=K < 10 6 + 3). The following line contains n numbers v i(1 <= v i < 10 6 + 3), where vi indicates the integer on vertex i. Then follows N - 1 lines. Each line contains two integers x and y, representing an undirected edge between vertex x and vertex y.
Output
For each test case, print a single line containing two integers a and b (where a < b), representing the two endpoints of the chain. If multiply solutions exist, please print the lexicographically smallest one. In case no solution exists, print “No solution”(without quotes) instead.
For more information, please refer to the Sample Output below.
Sample Input
5 60
2 5 2 3 3
1 2
1 3
2 4
2 5
5 2
2 5 2 3 3
1 2
1 3
2 4
2 5
Sample Output
3 4
No solution
Hint
1. “please print the lexicographically smallest one.”是指: 先按照第一個數字的大小進行比較,若第一個數字大小相同,則按照第二個數字大小進行比較,依次類推。
2. 若出現棧溢出,推薦使用C++語言提交,并通過以下方式擴棧:
#pragma comment(linker,"/STACK:102400000,102400000")

題目分析

很清晰應該使用樹分治,但是不同于一般樹分治的是這里要求我們記錄兩個點的位置。這就意味這不能直接套之前的模板,而必須做出一些變通。

首先,求重心、進行分治應該是沒有變化的,變的是對每個重心進行處理的部分。我們要把握住問題的難點在于如果記錄答案的話,我們如何記錄兩個端點以及如何處理記錄以后去掉子樹中重復的操作

一般的樹分治先將以重心為根的路徑全部遍歷一遍,將所有符合要求的答案保存,然后再在相同參數下遍歷子樹,將子樹中滿足條件的(說明剛才重復計算的部分)去掉。最后得到的就是答案。然而我們這里需要記錄答案,樸素的想法就是同樣將所有符合的都記錄下來(同時記錄兩個端點),然后再在子樹中將這些答案刪除。可是這種刪除將會非常耗費時間,我們必須在那個暫時保存答案的集合里面找到同一對數,最快也得O(nlogn),更何況我們這個操作要進行很多次。肯定會超時,所以我們必須換一個思路思考這個問題。

必須要刪除的核心關鍵在于我們在第一次訪問重心的時候沒有辦法判斷是否在同一個子樹上,所以只能先加上再減去。有沒有方法能夠避免計算同一個子樹上的答案呢?

我原本的想法是每次訪問重心得到其他點到重心的距離前先訪問一次重心進行染色,將每個子樹染成不同的顏色,然后再處理數據的時候再判斷是否在同一個子樹上來判斷是否是有效數據。可是題目要求記錄的是乘積等于k的字典序最小的一對端點。我們這樣做就必須記錄下所有的端點,答案可能很多,先不說存的下不,僅僅是記錄的操作估計都會超時。

不得已我上網看了以下其他人是怎么做的。他們的做法很巧妙,也讓我對樹分治有了更深刻的理解。

首先,我們必須扭轉將所有路徑的答案都記錄下來再進行處理的觀念。這樣對于只是求路徑個數的可能沒有什么問題,但是對于這種需要具體得到兩個端點的情況會超時。所以我們必須可以在某一端點處直接判斷是否存在有其他端點可以和它湊成答案。為了達到這個效果我們用一個數組T記錄以當前重心為根的情況下各個端點距離重心距離x所對應的端點為T[x],因為最后需要的是字典序最小的,所以我們保存所有T[x]中最小的就可以。然后對于每一個端點我們得到它的距離Dis[i]以后判斷是否有其他端點到樹根的距離為x使得Dis[i]*x==k,為了快速得到這個x,我們需要預處理以下乘法逆元Rev[]。則和端點i對應的端點就應該是T[Rev[Dis[x]]]。如果i和對應的端點都存在則和當前答案比較,確定是否更新答案。

如果不清楚什么是乘法逆元可以看一下我的這篇博客:逆元

可是這算是解決了如何存儲兩個端點的問題。但是如何消除同一個子樹中的端點的影響呢?我們的做法是不再像之前一樣一下遍歷所有的節點了,而是一個子樹一個子樹的遍歷。并且對T數組的更新放在對答案的判斷之后。這樣做的原因是訪問一個子樹的時候,他們這個字數上的信息沒有被更新到T數組中,因此T數組中保存的就是前面的子樹的信息,也就不會出現訪問到同一個子樹的情況啦。

在每次開始分治,我們的T數組應該是互相沒有聯系的,因此需要進行清空

同時我們用一個棧來保存訪問子樹中所有節點的信息,先更新答案后再更新T數組。

還需要注意一點的是我們的信息是保存在節點上的,因此根節點的信息先不要傳遞,在更新答案的時候再算上就可以啦。

AC代碼

#pragma comment(linker,"/STACK:102400000,102400000") #include<iostream> #include<cstring> #include<cstdio> #include<climits> #include<algorithm> #include<ctime> #include<cstdlib> #include<queue> #include<set> #include<map> #include<cmath>#define RG register #define IL inlineusing namespace std; typedef long long ll; const int MAXN=2e5+5; const int MOD=1e6+3; struct edge {int to,last; }Edge[MAXN<<2]; int Last[MAXN],tot; int n,kk,SonNum[MAXN],MaxNum[MAXN],Vis[MAXN]; int root,rootx,dlen,ss,len; ll Dis[MAXN],Rev[MOD+5],Num[MAXN]; int Stack[MAXN],T[MOD+5]; int top; int ansl,ansr;IL int getint() {int x=0,sign=1; char c=getchar();while(c<'0' || c>'9'){if(c=='-') sign=-1; c=getchar();}while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+c-'0'; c=getchar();}return x*sign; } IL ll getll() {ll x=0,sign=1; char c=getchar();while(c<'0' || c>'9'){if(c=='-') sign=-1; c=getchar();}while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+c-'0'; c=getchar();}return x*sign; }IL void Init() {for(int i=0;i<=n;++i) Last[i]=0,Vis[i]=false;tot=0; ansl=ansr=INT_MAX; }IL void AddEdge(int u,int v) {Edge[++tot].to=v; Edge[tot].last=Last[u]; Last[u]=tot; }IL void Read() {for(RG int i=1;i<=n;++i) Num[i]=getll();int u,v;for(RG int i=1;i<n;i++){u=getint(); v=getint();AddEdge(u,v); AddEdge(v,u);} }void GetRoot(int x,int father) {int v;SonNum[x]=1; MaxNum[x]=1;for(int i=Last[x];i;i=Edge[i].last){v=Edge[i].to; if(v==father || Vis[v]) continue;GetRoot(v,x);SonNum[x]+=SonNum[v];if(SonNum[v]>MaxNum[x]) MaxNum[x]=SonNum[x];}MaxNum[x]=max(MaxNum[x],ss-SonNum[x]);if(rootx>MaxNum[x]) root=x,rootx=MaxNum[x]; }void GetDis(int x,int father,ll now) {ll t=now*Num[x]%MOD;Dis[x]=t; Stack[top++]=x;int v;for(RG int i=Last[x];i;i=Edge[i].last){v=Edge[i].to; if(v==father|| Vis[v]) continue;GetDis(v,x,t);} }void Update(ll x,ll y,int z) {int tmp=T[Rev[x*y%MOD]*kk%MOD];if(!tmp) return;if(z>tmp) swap(z,tmp);if(z<ansl || z==ansl&&tmp<ansr) ansl=z,ansr=tmp; }void Solve(int x) {//memset(Dis,0,sizeof(Dis));int v;T[1]=x;Vis[x]=true;for(RG int i=Last[x];i;i=Edge[i].last){dlen=0; top=0;v=Edge[i].to; if(Vis[v]) continue;GetDis(v,x,1);for(RG int j=0;j<top;++j) Update(Num[x],Dis[Stack[j]],Stack[j]);for(RG int j=0;j<top;++j) if(T[Dis[Stack[j]]]==0 || T[Dis[Stack[j]]]>Stack[j]) T[Dis[Stack[j]]]=Stack[j];}for(int i=Last[x];i;i=Edge[i].last){dlen=0; top=0;v=Edge[i].to; if(Vis[v]) continue;GetDis(v,x,1);for(int j=0;j<top;++j) T[Dis[Stack[j]]]=0;}for(int i=Last[x];i;i=Edge[i].last){v=Edge[i].to; if(Vis[v]) continue;//ans-=Count(v,Deal(x,0));ss=SonNum[v]; rootx=INT_MAX; root=0;GetRoot(v,x);Solve(root);} }IL void Work() {rootx=INT_MAX; ss=n; root=0; GetRoot(1,0); Solve(root); }IL void Write() {if(ansl==INT_MAX && ansr==INT_MAX){printf("No solution\n");}else{printf("%d %d\n",ansl,ansr);} }IL void Pre() {Rev[1]=1;for(ll i=2;i<MOD;++i)Rev[i]=(MOD-MOD/i)*Rev[MOD%i]%MOD; }int main() {Pre();while(~scanf("%d%d",&n,&kk)){Init();Read();Work();Write();}return 0; }

經驗總結

對于一個問題首先要抽象出來需要用那種算法進行解決。局部的處理常常需要其他算法和數據結構的優化。盡可能不適用map和set等,能用數組還是盡量用數組。對數組的初始化也需要講究技巧,不能簡單使用一個memset,這種做法很容易超時。

總結

以上是生活随笔為你收集整理的HDU4812-D Tree-树分治的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 深夜福利视频在线 | 青青福利视频 | 久久一区二区三区视频 | 久久久成人精品视频 | 成人在线观看18 | 综合激情久久 | 欧美日韩在线精品 | 国产欧美一区二区三区鸳鸯浴 | 亚洲第六页 | www噜噜噜| 亲子乱子伦xxxx | 天天做天天操 | 精品国产黄 | 久久国产精品偷 | 欧美片网站yy | 羞羞涩| 吻胸摸激情床激烈视频大胸 | 欧美日韩999| 日韩少妇裸体做爰视频 | 欧美精品福利视频 | 超碰在线9 | 欧美性插视频 | 国产精品久久久久久网站 | 日韩免费av| 乱色专区| 久久国产一级片 | 国产精品色婷婷99久久精品 | 日韩免费播放 | 一区二区三区在线观看视频 | 捆绑凌虐一区二区三区 | 中文字幕在线观看一区二区三区 | 极品人妻videosss人妻 | 黄色大片儿 | 精品少妇人妻av一区二区三区 | 婷婷丁香久久 | 亚洲熟女乱色综合亚洲av | 91精品国产一区二区三竹菊影视 | 亚洲日本一区二区三区 | 一道本在线观看视频 | 久久男人的天堂 | 李华月全部毛片 | 国产午夜一级一片免费播放 | 欧美成年人视频在线观看 | 韩国成人理伦片免费播放 | 97se亚洲综合| 少妇高潮惨叫久久久久 | 久久精品久久久精品美女 | 欧美精品入口蜜桃 | 亚洲AV无码一区二区伊人久久 | 丰满秘书被猛烈进入高清播放在 | 性按摩玩人妻hd中文字幕 | 国产在线观看免费av | 99re在线视频免费观看 | 91高清免费视频 | 欧美做爰xxxⅹ性欧美大片 | 成人深夜免费视频 | 国产一区二区播放 | 综合激情四射 | 国产精品久久久免费 | 久久久久人妻精品一区二区三区 | 日韩中文一区 | 久久有精品 | 岛国av噜噜噜久久久狠狠av | 欧美一区二区三区粗大 | 久久777 | 啪一啪在线 | 亚洲视频图片 | 久久这里只有精品8 | 先锋资源av在线 | 中国女人黄色大片 | 午夜男人影院 | 国产精品第100页 | 奇米影视9999 | 熟妇高潮精品一区二区三区 | 国产无遮挡aaa片爽爽 | 亚洲最大色网站 | 欧美国产一区二区在线观看 | 秋霞午夜鲁丝一区二区老狼 | 欧美精品人妻一区二区 | 91av精品| 丁香久久婷婷 | 国内偷拍一区 | 亚洲国产精品一区二区久久hs | av中文字幕免费观看 | 欧美一区二区福利 | 国产免费自拍 | 亚洲第一黄 | 在线视频久 | 久久国产成人精品av | 四虎首页 | 欧美日韩小视频 | 亚洲人 女学生 打屁股 得到 | 国内自拍视频在线观看 | 亚州av免费 | 国产精品污视频 | 免费吸乳羞羞网站视频 | 国产一级18片视频 | 国产欧美精品一区二区 | 久久精品超碰 |