BZOJ:5457: 城市(线段树合并)(尚待优化)

5457: 城市

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 18  Solved: 12
[Submit][Status][Discuss]

Description

有n座城市,m个民族。这些城市之间由n-1条道路连接形成了以城市1为根的有根树。每个城市都是某一民族的聚居
地,Master知道第i个城市的民族是A_i,人数是B_i。为了维护稳定,Master需要知道某个区域内人数最多的民族
。他向你提出n个询问,其中第i个询问是:求以i为根的子树内,人数最多的民族有是哪个,这个民族有多少人。
如果子树内人数最多的民族有多个,输出其中编号最小的民族。

Input

共有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。

Output

共有n行。
第i行两个整数x, y,分别表示以i为根的子树中人数最多的民族和它的人数。

Sample Input

8 6
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

Sample Output

2 13
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;
}

猜你喜欢

转载自www.cnblogs.com/hua-dong/p/9960960.html