• 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;
    }
    

      

  • 相关阅读:
    table表框去掉相邻的间隔
    各种日期格式化返回
    校验金额、大小写字母、大写字母、合法uri、email
    vue js校验金钱、数字
    vue-router 动态添加 路由
    可视化-echarts流向图制作
    HTTP状态码
    二分查找
    编程语言的变量为啥不能是数字开头
    python位运算
  • 原文地址:https://www.cnblogs.com/liulangye/p/2633729.html
Copyright © 2020-2023  润新知