• HNOI 2016 地图


    【题目描述】

    Hoshizora Rin是个特别好动的少女。

    一天Rin来到了一个遥远的都市。这个都市有N个建筑,编号从1N,其中市中心编号为1,这个都市有M条双向通行的街道,每条街道连接着两个建筑,其中某些街道首尾相连连接成了一个环。Rin通过长时间的走访,已经清楚了这个都市的两个特点:

    1. 从市中心出发可以到达所有的建筑物。
    2. 任意一条街道最多存在与一个简单环中。

    Rin心花怒放的是,每个建筑物都会有拉面售卖。拉面有很多不同的种类,但对于Rin而言只有油腻程度的不同,因此我们把油腻程度相同的拉面看做同一种拉面。由于不同建筑物的拉面的油腻程度可能不同,我们用一个正整数来表示拉面的油腻程度。

    要知道,拉面可是Rin的最爱,但是现在到了下班高峰期,都市的交通变得非常的堵塞。Rin只能通过没有被堵死的街道通行,去品尝所在建筑物的拉面。

    现在Rin想知道,如果她正在编号为x的建筑物,那么在从市中心到x的所有简单路径经过的街道都被堵死的情况下,Rin可以品尝到的拉面中(注意没有出现的拉面是不能算在里面的):

    1. 油腻程度y且品尝次数为奇数次的拉面有多少种?
    2. 油腻程度y且品尝次数为偶数次的拉面有多少种?

    【输入格式】

    第一行两个正整数N,M,含义如题所示。

    第二行一共N个正整数,第i个数Ai表示第i个建筑物出售的拉面的油腻程度。

    接下来M行,每行两个正整数x,y,表示在建筑物x,y之间有一条双向通行的街道。数据保证1x<yN

    接下来一行一个正整数Q,表示询问个数。

    接下来Q行每行三个非负整数ty,x,yx表示询问的建筑物编号,y表示油腻程度的限制,ty=0时表示询问偶数,ty=1表示询问奇数。

    【输出格式】

    一共Q行,对于每个询问输出一个答案。

    【样例输入】

    5 6
    2 1 6 7 7
    1 2
    1 3
    2 4
    4 5
    4 5
    1 3
    3
    0 3 2
    0 3 1
    0 1 7
    

    【样例输出】

    0
    0
    1
    

    【样例解释】

    3号建筑物只能到达它自己,而1号建筑物可以到达所有建筑物。

    【数据范围】

    提示:请注意数据范围中的,特殊条件中提到的y均为询问中的y,对于100%的数据,有y106

    对仙人掌进行了一遍dfs,得到dfs树

    对于每个环,dfs序最小的叫做环的环根

    在1到x的简单路径都不能走的限制下,从点x出发,能走到的点记为x的子树

    如果x在环上 且 x不是环根,那么x的子树为 dfs序大于x的dfs序 且 不和x在同一个环上的点

    如果x在环上 且 x是环根,那么所有dfs序大于x的dfs序的 点 都是x的子树

    也就是说,环上点的子树只能累积到环根那里

    定义 x的子树大小为son[x],x的dfs序为id[x]

    那么对于每一个询问,就是查询 区间[id[x],id[x]+son[x]-1] 内有多少个点的油腻度<=y 

    用莫队

    cnt[k] 表示 油腻度为k的点的个数

    对油腻度 也分块 统计 

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 100001
    #define M 150001
    using namespace std;
    int n,m;
    int o[N],oil[N];
    int tot,front[N],nxt[M<<1],to[M<<1];
    int dfn[N],low[N],dy[N];
    int id[N],son[N];
    int siz1,siz2;
    int ans[N],tmp,sum[2][N],cnt[N*10],bl[N];
    bool ins[N];
    struct node
    {
        int l,r,ty,lim,num;
    }e[N];
    void read(int &x)
    {
        x=0; char c=getchar(); 
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    void add(int u,int v)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
    }
    void tarjan(int now,int last)
    {
        dfn[now]=low[now]=++tot;
        dy[tot]=now;
        for(int i=front[now];i;i=nxt[i])
        {
            if(to[i]==last) continue;
            if(!dfn[to[i]]) 
            {
                tarjan(to[i],now);
                low[now]=min(low[now],low[to[i]]);
            }
            else  low[now]=min(low[now],dfn[to[i]]);
        }
    }
    void dfs(int now)
    {
        ins[now]=true;
        id[now]=++tot;
        son[now]++;
        for(int i=front[now];i;i=nxt[i])
         if(!ins[to[i]])
            if(low[to[i]]>=dfn[now]) 
             { 
                dfs(to[i]);
                son[now]+=son[to[i]];
             }
        for(int i=front[now];i;i=nxt[i])
         if(!ins[to[i]])
          {
               dfs(to[i]);
               son[dy[low[to[i]]]]+=son[to[i]];
          }
    }
    bool cmp(node p,node q)
    {
        if(bl[p.l]!=bl[q.l]) return bl[p.l]<bl[q.l];
        return  p.r<q.r;    
    }
    void up(int pos,bool ty)
    {
        int p=(oil[pos]-1)/siz2+1;
        if(ty)
        {
            if(cnt[oil[pos]]&1) --sum[1][p],++sum[0][p];
            else if(cnt[oil[pos]]) --sum[0][p],++sum[1][p];
            else ++sum[1][p];
            ++cnt[oil[pos]];
        }
        else 
        {
            if(cnt[oil[pos]]==1) --sum[1][p];
            else if(cnt[oil[pos]]&1) --sum[1][p],++sum[0][p];
            else --sum[0][p],++sum[1][p];
            --cnt[oil[pos]];
        }
    }
    bool cal(int x,bool ty)
    {
        tmp=0;
        int last=(x-1)/siz2+1;
        for(int i=1;i<last;i++) tmp+=sum[ty][i];
        for(int i=(last-1)*siz2+1;i<=x;i++) 
        if(cnt[i] && (cnt[i]&1)==ty) tmp++;
    }
    int main()
    {
        //freopen("map_2016.in","r",stdin);
        //freopen("map_2016.out","w",stdout);
        read(n); read(m);
        siz1=sqrt(n);
        for(int i=1;i<=n;i++) bl[i]=(i-1)/siz1+1;
        int maxn=0;
        for(int i=1;i<=n;i++) read(o[i]),maxn=max(maxn,o[i]);
        siz2=sqrt(maxn);
        int u,v;
        for(int i=1;i<=m;i++) read(u),read(v),add(u,v);
        tot=0; 
        tarjan(1,0); 
        tot=0;
        dfs(1);
        for(int i=1;i<=n;i++) oil[id[i]]=o[i];
        int q,x;
        read(q);
        for(int i=1;i<=q;i++)
        {
            read(e[i].ty);
            read(x);
            e[i].l=id[x];
            e[i].r=id[x]+son[x]-1;
            read(e[i].lim);
            e[i].num=i;
        }
        sort(e+1,e+q+1,cmp);
        int L=1,R=0;
        for(int i=1;i<=q;++i)
        {
            while(R<e[i].r) up(++R,true);
            while(L>e[i].l) up(--L,true);
            while(R>e[i].r) up(R--,false);
            while(L<e[i].l) up(L++,false);
            cal(e[i].lim,e[i].ty);
            ans[e[i].num]=tmp;
        }
        for(int i=1;i<=q;i++) printf("%d
    ",ans[i]);
    }
  • 相关阅读:
    搭建基于nginx-rtmp-module的流媒体服务器
    mysql length和char_length
    mediainfo使用
    linux下ftp服务器搭建
    排序算法
    设计模式之注册树模式
    dock
    linux下安装使用tar
    linux下安装rar
    linux 内存操作相关命令
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7388886.html
Copyright © 2020-2023  润新知