HNOI 2016 地图

【题目描述】

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

一天Rin来到了一个遥远的都市。这个都市有N个建筑,编号从1到N,其中市中心编号为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之间有一条双向通行的街道。数据保证1≤x<y≤N。

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

接下来Q行每行三个非负整数ty,x,y,x表示询问的建筑物编号,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%的数据,有y≤106。

对仙人掌进行了一遍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]);
}
时间: 2024-12-30 02:00:34

HNOI 2016 地图的相关文章

HNOI 2016 乱做

  4542: [Hnoi2016]大数 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 488  Solved: 182[Submit][Status][Discuss] Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也是P 的倍数).例如

HNOI 2016 省队集训日记

第一天 DeepDarkFantasy 从东京出发,不久便到一处驿站,写道:日暮里.  ——鲁迅<藤野先生> 定义一个置换的平方为对1~n的序列做两次该置换得到的序列.已知一个置换的平方,并且这个结果是一个排列,求该置换. 输入第一行一个数n表示排列长度,接下来一行n个数描述排列. 有解则输出一行n个数表示原排列.否则输出一行一个-1. 测试点编号 特征 0~1 n<=10 2~9 n<=1000000 此题有spj. 考试的时候懵逼了,根本没想清就开始乱打. 题解:由题易得每一个

【BZOJ 4539】【HNOI 2016】树

http://www.lydsy.com/JudgeOnline/problem.php?id=4539 今天测试唯一会做的一道题. 按题目要求,如果暴力的把模板树往大树上仍,最后得到的大树是$O(n^2)$级别的,不能存储,更不能做了. 把模板树往大树上扔的过程我想象成了两个大节点进行连边,每个大节点代表模板树本身或一部分. 这相当于把初始的大树(此时和模板树相同)缩成一个大节点,每次把模板树的一部分缩成一个大节点往大节点构成的大树上连,最后连好的大节点构成的模板树是$O(n)$级别的. 每个

数据结构(树链剖分,堆):HNOI 2016 network

2215. [HNOI2016]网络 ★★★☆   输入文件:network_tenderRun.in   输出文件:network_tenderRun.out   简单对比时间限制:2 s   内存限制:128 MB [题目描述] [输入格式] [输出格式] [样例输入1] 13 23 1 2 1 3 2 4 2 5 3 6 3 7 4 8 4 9 6 10 6 11 7 12 7 13 2 1 0 8 13 3 0 9 12 5 2 9 2 8 2 2 0 10 12 1 2 2 1 3 2

[HNOI 2016]大数

Description 题库链接 给你一个长度为 \(n\) ,可含前导零的大数,以及一个质数 \(p\) . \(m\) 次询问,每次询问你一个大数的子区间 \([l,r]\) ,求出子区间中有多少个子串为 \(p\) 的倍数. \(1\leq n,m\leq 100000\) Solution 记 \(a_i\) 为大数第 \(i\) 位上的数值. 注意到题目是要求 \[\sum_{i=l}^r\sum_{j=i}^r\left[\sum_{k=i}^ja_k\cdot 10^{j-k}\e

[HNOI 2016]序列

Description 题库链接 给你一个长度为 \(n\) 的序列 \(A\) ,给出 \(q\) 组询问.每次询问 \([l,r]\) ,求该区间内所有的子序列中最小值的和. \(1\leq n,q\leq 100000,|A_i|\leq 10^9\) Solution 考虑把右端点右移时,会产生 \(r-l+1\) 个新的区间,我们可以来统计这 \(r-l+1\) 个区间的最小值和. 记 \(pre_i\) 为从第 \(i\) 位往左走第一个值比 \(A_i\) 小的位置. 显然在 \(

[HNOI 2016]最小公倍数

Description 题库链接 给定一张 \(N\) 个顶点 \(M\) 条边的无向图(顶点编号为 \(1,2,\cdots,n\) ),每条边上带有权值.所有权值都可以分解成 \(2^a\times 3^b\) 的形式. \(q\) 个询问,每次询问给定四个参数 \(u,v,a,b\) ,请你求出是否存在一条顶点 \(u\) 到 \(v\) 之间的路径,使得路径依次经过的边上的权值的最小公倍数为 \(2^a\times 3^b\) . \(1\leq n,q\leq 50000,1\leq

聊一聊前端模板与渲染那些事儿

欢迎大家收看聊一聊系列,这一套系列文章,可以帮助前端工程师们了解前端的方方面面(不仅仅是代码): https://segmentfault.com/blog/frontenddriver 作为现代应用,ajax的大量使用,使得前端工程师们日常的开发少不了拼装模板,渲染模板.我们今天就来聊聊,拼装与渲染模板的那些事儿. 如果喜欢本文请点击右侧的推荐哦,你的推荐会变为我继续更文的动力 1 页面级的渲染 在刚有web的时候,前端与后端的交互,非常直白,浏览器端发出URL,后端返回一张拼好了的HTML串

使用 Raspberry Pi 上的传感器在 Node.js 中创建一个 IoT Bluemix 应用程序

先决条件 一个IBM Bluemix 帐号,一个 Raspberry Pi 2 或 3,一个 PIR 运动传感器 适用于本文的 Github 存储库 如果您是一位精明的 Bluemix 开发人员,您可能只想看看如何在 node.js 中与 IoT 建立连接,或者只想了解如何从此 github 存储库中拉取我的代码. git clone https://github.com/nicolefinnie/iot-nodejs-tutorial 以下是实现与 IBM IoT 平台连接在一起的 4 个 R