• 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
    ",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
    ",ans[i][0],ans[i][1]);
        return 0;
    }
  • 相关阅读:
    Python笔记_第一篇_面向过程_第一部分_5.Python数据类型之字符串类型(string)
    每天一杯C_Visual Studio各个版本的区别和总结
    Python笔记_第一篇_面向过程_第一部分_5.Python数据类型之数字类型(number)
    Python笔记_第一篇_面向过程_第一部分_3.进制、位运算、编码
    Valid Number @python
    正式进驻博客园
    LCT总结
    LCT总结
    bzoj3229 [Sdoi2008]石子合并(非dp的GarsiaWachs算法)
    bzoj3229 [Sdoi2008]石子合并(非dp的GarsiaWachs算法)
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9960960.html
Copyright © 2020-2023  润新知