BZOJ:5457: 城市(線段樹合並)(尚待優化)
阿新 • • 發佈:2018-11-15
size EDA max bzoj turn dfs insert 優化 next
Submit: 18 Solved: 12
[Submit][Status][Discuss]
共有2*n行。
第一行有兩個整數n, m。
接下來n-1行,每行有兩個整數u, v,表示一條連接u和v的道路。
接下來n行,第i行有兩個整數A_i, B_i。
n<=400000,m<=n,1<=A_i<=m,0<=B_i<=1000。
1 2
1 3
2 4
4 5
3 6
5 7
1 8
2 8
2 5
1 1
3 1
6 7
5 6
1 10
4 6
2 13
1 10
5 6
1 10
1 10
5 6
1 10
4 6
5457: 城市
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 18 Solved: 12
[Submit][Status][Discuss]
Description
有n座城市,m個民族。這些城市之間由n-1條道路連接形成了以城市1為根的有根樹。每個城市都是某一民族的聚居 地,Master知道第i個城市的民族是A_i,人數是B_i。為了維護穩定,Master需要知道某個區域內人數最多的民族 。他向你提出n個詢問,其中第i個詢問是:求以i為根的子樹內,人數最多的民族有是哪個,這個民族有多少人。 如果子樹內人數最多的民族有多個,輸出其中編號最小的民族。Input
Output
共有n行。 第i行兩個整數x, y,分別表示以i為根的子樹中人數最多的民族和它的人數。Sample Input
8 61 2
1 3
2 4
4 5
3 6
5 7
1 8
2 8
2 5
1 1
3 1
6 7
5 6
1 10
4 6
Sample Output
1 10
5 6
1 10
1 10
5 6
1 10
4 6
思路:每個節點保存一個線段樹,表示子樹的民族及其數量,維護區間最大值。
然後DFS,線段樹合並即可。 7500ms。再8個AC裏,我的三個AC代碼分別排最後三名。 亟待優化啊!
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int inf=0x3f3f3f3f; const int maxn=800010; void read(int &x){ x=0; char c=getchar(); while(c>‘9‘||c<‘0‘) c=getchar(); while(c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar(); } struct in{ int l,r,pos,mx; in(){l=r=mx=pos=0;} }s[maxn*20]; int Laxt[maxn],Next[maxn],To[maxn],cnt,M; int A[maxn],B[maxn],rt[maxn],tot,ans[maxn][2]; void add(int u,int v){ Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } void pushup(int Now){ if(s[Now].l&&!s[Now].r){ s[Now].mx=s[s[Now].l].mx; s[Now].pos=s[s[Now].l].pos; } else if(s[Now].l&&s[Now].r&&s[s[Now].l].mx>=s[s[Now].r].mx){ s[Now].mx=s[s[Now].l].mx; s[Now].pos=s[s[Now].l].pos; } else s[Now].mx=s[s[Now].r].mx,s[Now].pos=s[s[Now].r].pos; } void insert(int &Now,int L,int R,int pos,int num) { if(!Now) Now=++tot; if(L==R){ s[Now].mx=num; s[Now].pos=L; return ;} int Mid=(L+R)>>1; if(pos<=Mid) insert(s[Now].l,L,Mid,pos,num); else insert(s[Now].r,Mid+1,R,pos,num); pushup(Now); } int merge(int x,int y,int L,int R){ if(!x||!y) return x|y; if(L==R) { s[x].mx+=s[y].mx; return x;} int Mid=(L+R)>>1; s[x].l=merge(s[x].l,s[y].l,L,Mid); s[x].r=merge(s[x].r,s[y].r,Mid+1,R); pushup(x); return x; } void dfs(int u,int f){ for(int i=Laxt[u];i;i=Next[i]){ int v=To[i]; if(v==f) continue; dfs(v,u); rt[u]=merge(rt[u],rt[v],1,M); } ans[u][1]=s[rt[u]].mx; ans[u][0]=s[rt[u]].pos; } int main() { int N,u,v; scanf("%d%d",&N,&M); rep(i,1,N-1){ read(u); read(v); add(u,v); add(v,u); } rep(i,1,N) read(A[i]),read(B[i]); rep(i,1,N) insert(rt[i],1,M,A[i],B[i]); dfs(1,0); rep(i,1,N) printf("%d %d\n",ans[i][0],ans[i][1]); return 0; }
然後想著每一層,我先合並子樹大小較小的。 即按sz排序後再合並,和上次一樣,並沒有優化。 7988ms
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int inf=0x3f3f3f3f; const int maxn=800010; void read(int &x){ x=0; char c=getchar(); while(c>‘9‘||c<‘0‘) c=getchar(); while(c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar(); } struct in{ int l,r,pos,mx; in(){l=r=mx=pos=0;} }s[maxn*20]; int Laxt[maxn],Next[maxn],To[maxn],cnt,M,sz[maxn]; int A[maxn],B[maxn],rt[maxn],tot,ans[maxn][2]; void add(int u,int v){ Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } void pushup(int Now){ if(s[Now].l&&!s[Now].r){ s[Now].mx=s[s[Now].l].mx; s[Now].pos=s[s[Now].l].pos; } else if(s[Now].l&&s[Now].r&&s[s[Now].l].mx>=s[s[Now].r].mx){ s[Now].mx=s[s[Now].l].mx; s[Now].pos=s[s[Now].l].pos; } else s[Now].mx=s[s[Now].r].mx,s[Now].pos=s[s[Now].r].pos; } void insert(int &Now,int L,int R,int pos,int num) { if(!Now) Now=++tot; if(L==R){ s[Now].mx=num; s[Now].pos=L; return ;} int Mid=(L+R)>>1; if(pos<=Mid) insert(s[Now].l,L,Mid,pos,num); else insert(s[Now].r,Mid+1,R,pos,num); pushup(Now); } int merge(int x,int y,int L,int R){ if(!x||!y) return x|y; if(L==R) { s[x].mx+=s[y].mx; return x;} int Mid=(L+R)>>1; s[x].l=merge(s[x].l,s[y].l,L,Mid); s[x].r=merge(s[x].r,s[y].r,Mid+1,R); pushup(x); return x; } void dfs1(int u,int f){ sz[u]=1; for(int i=Laxt[u];i;i=Next[i]){ if(To[i]!=f) dfs1(To[i],u); sz[u]+=sz[To[i]]; } } bool cmp(int w,int v){ return sz[w]<sz[v]; } void dfs2(int u,int f){ cnt=0; vector<int>G; for(int i=Laxt[u];i;i=Next[i]){ if(To[i]!=f) G.push_back(To[i]); } sort(G.begin(),G.end(),cmp); for(int i=0;i<G.size();i++){ int v=G[i]; dfs2(v,u); rt[u]=merge(rt[u],rt[v],1,M); } ans[u][1]=s[rt[u]].mx; ans[u][0]=s[rt[u]].pos; } int main() { int N,u,v; scanf("%d%d",&N,&M); rep(i,1,N-1){ read(u); read(v); add(u,v); add(v,u); } rep(i,1,N) read(A[i]),read(B[i]); rep(i,1,N) insert(rt[i],1,M,A[i],B[i]); dfs1(1,0); dfs2(1,0); rep(i,1,N) printf("%d %d\n",ans[i][0],ans[i][1]); return 0; }
BZOJ:5457: 城市(線段樹合並)(尚待優化)