HDU 4358 Boring Counting ★★(2012 Multi-University Training Contest 6)

问题抽象区间内恰好出现K次的数的个数。

------------------------------------------------------------------

UESTC出的题就是神啊T_T。。。一开始想了个函数式线段树方法后来发现错了=。=,然后也没什么思路,就是找着官方题解的方法做的。

思路:

 HDU 4358 Boring Counting ★★(2012 Multi-University Training Contest 6)

题解说的用树状数组,这里当然也可以用线段树维护,和上面一样,线段树第j个数表示区间[j, i]内出现k次的数有多少个,然后像题解一样维护即可。(这种维护方法值得好好研究&&学习呀~)

代码中也有比较详细的注释:

View Code
#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cmath>

#include <vector>

#include <stack>

#include <queue>

#include <map>

#include <algorithm>

#include <string>

#include <cstring>

#define MID(x,y) ((x+y)>>1)



using namespace std;

const int maxn = 100100;



int id,n,K;

int ans[maxn];

int w[maxn],wb[maxn];

int vis[maxn];

int a[maxn];            //线性权值

int l[maxn],r[maxn];    //线性区间

vector <int> v[maxn];   //边表

vector <int> pos[maxn]; //记录某数出现的位置

int num[maxn];          //记录某个数出现多少次了

map <int, int>  M;      //离散化

int mtot;



struct ANS

{

    int l,r;

    int id;

}Q[maxn];



bool cmp(ANS a1, ANS a2)

{

    return a1.r<a2.r;

}



void dfs(int x)

{

    // 将树形结构变成线性结构

    if (!vis[x])

    {

        id ++;

        l[x] = id;

        a[id] = w[x];

        vis[x] = 1;

        vector <int> ::iterator vp;

        if (v[x].size())

            for (vp = v[x].begin(); vp != v[x].end(); vp ++)

                dfs(*vp);

        r[x] = id;

    }

}



int sum[maxn<<2],add[maxn<<2];

void build(int l,int r,int rt)

{

    sum[rt] = 0;

    add[rt] = 0;

    if (l == r)  return ;

    int mid = MID(l,r);

    build(l,mid,rt<<1);

    build(mid+1,r,rt<<1|1);

}

void pushdown(int rt,int w)

{

    if (add[rt])

    {

        add[rt<<1] += add[rt];

        add[rt<<1|1] += add[rt];

        sum[rt<<1] += add[rt] * (w - (w >> 1));

        sum[rt<<1|1] += add[rt] * (w >> 1);

        add[rt] = 0;

    }

}

void update(int s,int t,int v,int l,int r,int rt)

{

    if (s <= l && r <= t)

    {

        sum[rt] += v * (r - l + 1);

        add[rt] += v;

        return ;

    }

    pushdown(rt, r-l+1);

    int mid = MID(l,r);

    if (s <= mid)   update(s,t,v,l,mid,rt<<1);

    if (mid < t)    update(s,t,v,mid+1,r,rt<<1|1);

}

int query(int p,int l,int r,int rt)

{

    if (l == p && r == p)

    {

        return sum[rt];

    }

    pushdown(rt,r-l+1);

    int mid = MID(l,r);

    if (p <= mid)   return query(p,l,mid,rt<<1);

    else return query(p,mid+1,r,rt<<1|1);

}

int main()

{

    //freopen("data.txt","r+",stdin);

    int tt,caseo = 1;

    scanf("%d",&tt);

    while(tt--)

    {

        //Initialize

        mtot = id = 0;

        memset(v,0,sizeof(v));

        memset(vis,0,sizeof(vis));

        memset(pos,0,sizeof(pos));

        memset(num,0,sizeof(num));

        //input

        printf("Case #%d:\n",caseo ++);

        scanf("%d%d",&n,&K);

        for (int i = 1; i <= n; i ++)

            scanf("%d",&w[i]);

        for (int i = 1; i < n; i ++)

        {

            int a,b;

            scanf("%d%d",&a,&b);

            v[a].push_back(b);  //边表

        }

        //树形结构转线性结构

        dfs(1);

        M.clear();



        //权值离散化

        for (int i = 1; i <= n; i ++)

            if (!M[a[i]])   M[a[i]] = ++ mtot;



        int q;

        scanf("%d",&q);

        for (int i = 0; i < q; i ++)

        {

            int p;

            scanf("%d",&p);

            Q[i].l = l[p];

            Q[i].r = r[p];

            Q[i].id = i;

        }

        sort(Q,Q+q,cmp);

        int pt = 0;

        build(1,n,1);

        for (int i = 1; i <= n; i ++)

        {

            pos[M[a[i]]].push_back(i);

            num[M[a[i]]] ++;

            if (num[M[a[i]]] >= K)

                if (num[M[a[i]]] == K)

                    update(1,pos[M[a[i]]][0],1,1,n,1);

                else

                {

                    int ss = (num[M[a[i]]] - K <= 2)?1:(num[M[a[i]]] - K - 2);

                    update(ss,pos[M[a[i]]][num[M[a[i]]]-K-1],-1,1,n,1);

                    update(pos[M[a[i]]][num[M[a[i]]]-K-1]+1,pos[M[a[i]]][num[M[a[i]]]-K],1,1,n,1);

                }

            else;

            while(pt < q && Q[pt].r == i)

            {

                ans[Q[pt].id] = query(Q[pt].l,1,n,1);

                pt ++;

            }

        }

        for (int i = 0; i < q; i ++)

            printf("%d\n",ans[i]);

        if (tt) printf("\n");

    }

    return 0;

}

 

你可能感兴趣的:(count)