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\n",ans[i]);
}

 

posted @ 2017-08-18 11:56  TRTTG  阅读(477)  评论(0编辑  收藏  举报