bzoj 1468 Tree(点分治模板)
生活随笔
收集整理的這篇文章主要介紹了
bzoj 1468 Tree(点分治模板)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?
1468: Tree
Time Limit:?10 Sec??Memory Limit:?64 MBSubmit:?1527??Solved:?818
[Submit][Status][Discuss]
Description
給你一棵TREE,以及這棵樹上邊的距離.問有多少對點它們兩者間的距離小于等于KInput
N(n<=40000) 接下來n-1行邊描述管道,按照題目中寫的輸入 接下來是kOutput
一行,有多少對點之間的距離小于等于kSample Input
71 6 13
6 3 9
3 5 7
4 1 3
2 4 20
4 7 2
10
Sample Output
5 /* 思路: 最容易想到的算法是:從每個點出發遍歷整棵樹,統計數對個數。 由于時間復雜度O(N^2),明顯是無法滿足要求的。對于一棵有根樹, 樹中滿足要求的一個數對所對應的一條路徑,必然是以下兩種情況之一: 1、經過根節點 2、不經過根節點,也就是說在根節點的一棵子樹中 對于情況2,可以遞歸求解,下面主要來考慮情況1。設點i的深度為Depth[i],父親為Parent[i]。 若i為根,則Belong[i]=-1,若Parent[i]為根,則Belong[i]=i,否則Belong[i]=Belong[Parent[i]]。 這三個量都可以通過一次BFS求得。 我們的目標是要統計:有多少對(i,j)滿足i<j,Depth[i]+Depth[j]<=K且Belong[i]<>Belong[j]如果這樣考慮問題會變得比較麻煩,我們可以考慮換一種角度: 設X為滿足i<j且Depth[i]+Depth[j]<=K的數對(i,j)的個數 設Y為滿足i<j,Depth[i]+Depth[j]<=K且Belong[i]=Belong[j]數對(i,j)的個數 那么我們要統計的量便等于X-Y求X、Y的過程均可以轉化為以下問題: 已知A[1],A[2],...A[m],求滿足i<j且A[i]+A[j]<=K的數對(i,j)的個數對于這個問題,我們先將A從小到大排序。 設B[i]表示滿足A[i]+A[p]<=K的最大的p(若不存在則為0)。我們的任務便轉化為求出A所對應的B數組。那么,若B[i]>i,那么i對答案的貢獻為B[i]-i。 顯然,隨著i的增大,B[i]的值是不會增大的。利用這個性質,我們可以在線性的時間內求出B數組,從而得到答案。綜上,設遞歸最大層數為L,因為每一層的時間復雜度均為“瓶頸”——排序的時間復雜度O(NlogN),所以總的時間復雜度為O(L*NlogN)然而,如果遇到極端情況——這棵樹是一根鏈,那么隨意分割勢必會導致層數達到O(N)級別,對于N=10000的數據是無法承受的。因此,我們在每一棵子樹中選擇“最優”的點分割。所謂“最優”,是指刪除這個點后最大的子樹盡量小。這個點可以通過樹形DP在O(N)時間內求出,不會增加時間復雜度。這樣一來,即使是遇到一根鏈的情況時,L的值也僅僅是O(logN)的。因此,改進后算法時間復雜度為O(Nlog^2N),可以AC。 /* 學習 思路 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm>#define inf 0x3f3f3f3f #define maxn 40010using namespace std; struct node {int to,w,next; }e[maxn<<1]; int head[maxn],vis[maxn],son[maxn],deep[maxn],f[maxn],d[maxn]; int n,cnt,root,sum,K,ans,num,x,y,z,L;inline int read() {int x=0,f=1;char c=getchar();while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x*f; }inline void add(int u,int v,int dis) {e[++num].to=v;e[num].next=head[u];e[num].w=dis;head[u]=num; }inline void init() {cnt=ans=root=sum=0;memset(head,0,sizeof(head));memset(vis,0,sizeof(vis));memset(deep,0,sizeof(deep));for(int i=1;i<n;i++){x=read();y=read();z=read();add(x,y,z);add(y,x,z);} }void get_root(int now,int fa) {son[now]=1;f[now]=-1;for(int i=head[now];i;i=e[i].next){int v=e[i].to;if(vis[v]||v==fa) continue;get_root(v,now);son[now]+=son[v];f[now]=max(f[now],son[v]);}f[now]=max(f[now],sum-son[now]);if(f[now]<f[root]) root=now; }void get_deep(int now,int fa) {deep[++L]=d[now];for(int i=head[now];i;i=e[i].next){int v=e[i].to;if(vis[v]||v==fa) continue;d[v]=d[now]+e[i].w;get_deep(v,now);} }int cal(int now,int dis) {d[now]=dis;L=0;get_deep(now,-1);sort(deep+1,deep+L+1);int t=0;for(int l=1,r=L;l<r;){if (deep[l]+deep[r]<=K) t+=r-l,l++;else r--; }return t; }void work(int u) {ans+=cal(u,0);vis[u]=1;for(int i=head[u];i;i=e[i].next){int v=e[i].to;if(vis[v]) continue;ans-=cal(v,e[i].w);sum=son[v];root=0;get_root(v,0);work(root);} }int main() {freopen("data.txt","r",stdin);freopen("bzoj1468.txt","w",stdout);n=read();init();K=read();sum=n;f[0]=inf;get_root(1,-1);work(root);printf("%d\n",ans);return 0; } 代碼 #include<cstdio> #include<algorithm> #define N 40005 using namespace std; struct arr{int s,go,next;}a[N*2]; int end[N],son[N],f[N],d[N],data[N]; int cnt,L,All,ans,i,x,y,z,n,root,K; bool Can[N]; void add(int u,int v,int s) {a[++cnt].go=v;a[cnt].next=end[u];a[cnt].s=s;end[u]=cnt; }void Get_root(int k,int fa) {son[k]=1;f[k]=0;for (int i=end[k];i;i=a[i].next){int go=a[i].go;if (go==fa||Can[go]) continue;Get_root(go,k);son[k]+=son[go];if (son[go]>f[k]) f[k]=son[go];}if (All-son[k]>f[k]) f[k]=All-son[k];if (f[k]<f[root]) root=k; }void Get_array(int k,int fa) {data[++L]=d[k];for (int i=end[k];i;i=a[i].next){int go=a[i].go;if (go!=fa&&!Can[go]) d[go]=d[k]+a[i].s,Get_array(go,k);} }int calc(int k,int now) {d[k]=now;L=0;Get_array(k,-1);int A=0,l,r;sort(data+1,data+L+1);for (l=1,r=L;l<r;)if (data[r]+data[l]<=K) A+=(r-l),l++;else r--;return A; }void work(int k) {ans+=calc(k,0);Can[k]=1;for (int i=end[k];i;i=a[i].next){int go=a[i].go;if (Can[go]) continue;ans-=calc(go,a[i].s);f[root=0]=n+1;All=son[go];Get_root(go,-1);work(root);} }int main() {freopen("data.txt","r",stdin);freopen("1468.txt","w",stdout);scanf("%d",&n);for (i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);scanf("%d",&K);All=n;f[root=0]=n+1;Get_root(1,-1);work(root);printf("%d",ans);return 0; } 標程 #include <bits/stdc++.h>using namespace std;#define PaiChuCuoWuCaiBREAK trueint main() {while(PaiChuCuoWuCaiBREAK){system("data.exe");system("1468.exe");system("bzoj1468.exe");if(system("fc 1468.txt bzoj1468.txt")) {cout<<"lrhdsb";break;}}return 0; } 對拍 #include <bits/stdc++.h>using namespace std;#define maxn 10004 #define justval 68451 #define justval_ 15641684int l[maxn],r[maxn],n,lo,ro;int main() {freopen("data.txt","w",stdout);n=rand()%maxn+1;printf("%d\n",n);for(int i=1;i<n;i++) l[i]=i+1;lo=n-1,r[++ro]=1;for(int just=1;just<n;just++){int pos=rand()%lo+1;int pos_=rand()%ro+1;r[++ro]=l[pos];printf("%d %d %d\n",l[pos],r[pos_],rand()%justval);for(int i=pos;i<lo;i++) l[i]=l[i+1];lo--;}printf("%d\n",rand()%justval_);return 0; } 數據生成 一棵樹?
轉載于:https://www.cnblogs.com/L-Memory/p/6936115.html
總結
以上是生活随笔為你收集整理的bzoj 1468 Tree(点分治模板)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hibernate 管理 Session
- 下一篇: 微信小程序新增推广功能,支持自定义关键词