zoukankan      html  css  js  c++  java
  • hdu 4358 Boring counting 夜

    http://acm.hdu.edu.cn/showproblem.php?pid=4358

    map 版本  

    比赛的时候也用map 写了 不过没有加优化 所以超时了

    调试了一上午  下午自己出数据测了一下才知道那里出错了 汗

    大体思路:

    用map<int , int > 保存子树某个数出现的次数 然后从叶子节点向上更新合并 合并的时候需要 size小的向size大

    的上面合并 这样省时 这是由map 的构造决定的

    用c++ 提交要 手动开栈  否则会栈溢出  用G++ 提交可以避免但花费时间要长一些

    自测数据 对我来说很重要的一组数据 就是这里错了一上午

    1
    6 1
    1 2 3 4 5 6
    1 2
    1 3
    3 4
    3 5
    1 6
    6
    1
    2
    3
    4
    5
    6

    详情及其细节见代码及其注释:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #include<queue>
    #include<cmath>
    #define LL long long
    //#pragma comment(linker, "/STACK:102400000,102400000")//c++提交的话 需要手动开栈(看解析上的) g++不用 但时间花费长
    
    using namespace std;
    
    const int N=100005;
    int head[N];//邻接表 表头
    struct node
    {
        int j;
        int next;
    }side[N*2];
    int son[N];//儿子节点个数
    int f[N];//保存父节点
    int id[N];//某个节点对应相关数据存在了哪个map里面 由于合并的关系 刚开始 i和id[i]对应相等 但一定的合并后就变了
    int ans[N];//保存答案 离线保存要用
    map<int ,int>str[N];
    map<int ,int>:: iterator it,it1;
    queue<int>qu;
    int K;
    void build(int x,int i)
    {
        side[i].next=head[x];
        head[x]=i;
    }
    void dfs(int x,int pre)//用dfs求的本节点的父节点 和儿子节点数  和将叶子节点加入队列
    {
        int t=head[x];
        f[x]=pre;
        while(t!=-1)
        {
            if(side[t].j!=pre)
            {
              dfs(side[t].j,x);
              ++son[x];
            }
            t=side[t].next;
        }
        if(son[x]==0)
        {
            qu.push(x);
        }
    }
    void Add(int I,int i,int j)//将 map j 合并到i当中 将答案ans[I]进行更新
    {
        for(it=str[j].begin();it!=str[j].end();++it)//it 遍历map j 的元素
        {
            it1=str[i].find(it->first);//到i 中查询
            if(it1==str[i].end())//未找到
            {
                str[i][it->first]=it->second;//加入
                if(it->second==K)//如果正好等于K 则答案加一
                ++(ans[I]);
                continue;
            }
            if(it1->second==K)//如果找到 本来在i中 这个数出现次数正好为K 在加上一个非0数则不等于K 了所以答案个数减1
            --(ans[I]);
            if((it1->second+=it->second)==K)//如果加上正好为K 答案个数加1 这不会和上一个冲突
            ++(ans[I]);
        }
    }
    int main()
    {
        //freopen("data.txt","r",stdin);
        int T;
        scanf("%d",&T);
        for(int cas=1;cas<=T;++cas)
        {
            memset(head,-1,sizeof(head));
            memset(ans,0,sizeof(ans));
            memset(son,0,sizeof(son));//各种初始化
            while(!qu.empty())
            qu.pop();
            int n,q;
            scanf("%d %d",&n,&K);
            for(int i=1;i<=n;++i)
            {
                int a;
                str[i].clear();//清空
                id[i]=i;//本来每个节点 的map 就是自己对应的
                scanf("%d",&a);
                str[i][a]=1;//先都加入 本节点的数
                if(K==1)//如果K正好为1 则答案也更新
                ++ans[i];
            }
            int x,y;
            for(int i=1;i<n;++i)//输入边 建树
            {
                scanf("%d %d",&x,&y);
                side[i].j=y;
                build(x,i);
                side[i+n].j=x;
                build(y,i+n);/
            }
            dfs(1,0);//搜一个
            while(!qu.empty())
            {
                int l=qu.front();//取元素
                if(l==1)
                break;//如果到了1 则全求出 可以停止
                qu.pop();
                int fa=f[l];//fa为父亲节点
                --son[fa];//父亲节点的可以更新的儿子节点减少1
                if(son[fa]==0)//这是最后一个儿子节点 这是将fa加入队列 千万不能第一次更新就加入 
                {//否则会出现父节点在儿子节点前面的情况 就错了(自己输在这里了)  见上面数据
                    qu.push(fa);
                }
                int li=id[l];//找到对应的map 
                int fai=id[fa];
                if(str[fai].size()>str[li].size())//比较大小
                {
                    Add(fa,fai,li);
                }else
                {
                    ans[fa]=ans[l];//如果需要往l上合并 则先等于l的ans 在下面更新后ans[fa] 始终保存当前对应map里面的答案
                    id[fa]=li;//更改对应的map
                    Add(fa,li,fai);//更新
                }
            }
            scanf("%d",&q);
            printf("Case #%d:\n",cas);
            while(q--)
            {
                scanf("%d",&x);
                printf("%d\n",ans[x]);
            }
            if(cas<T)
            printf("\n");
        }
    
        return 0;
    }
    

      

  • 相关阅读:
    mysql 远程登陆不上
    hdu 5339 Untitled【搜索】
    SqlServer 书目
    passwordauthentication yes
    oracle 11g RAC ocfs2
    Oracle 11g RAC database on ASM, ACFS or OCFS2
    CentOS ips bonding
    Oracle 11g RAC features
    openStack 王者归来之 trivial matters
    openstack windows 2008 img
  • 原文地址:https://www.cnblogs.com/liulangye/p/2633729.html
Copyright © 2011-2022 走看看