HNOI 2016 地图
【题目描述】
Hoshizora Rin是个特别好动的少女。
一天Rin来到了一个遥远的都市。这个都市有N个建筑,编号从1到N,其中市中心编号为1,这个都市有M条双向通行的街道,每条街道连接着两个建筑,其中某些街道首尾相连连接成了一个环。Rin通过长时间的走访,已经清楚了这个都市的两个特点:
- 从市中心出发可以到达所有的建筑物。
- 任意一条街道最多存在与一个简单环中。
令Rin心花怒放的是,每个建筑物都会有拉面售卖。拉面有很多不同的种类,但对于Rin而言只有油腻程度的不同,因此我们把油腻程度相同的拉面看做同一种拉面。由于不同建筑物的拉面的油腻程度可能不同,我们用一个正整数来表示拉面的油腻程度。
要知道,拉面可是Rin的最爱,但是现在到了下班高峰期,都市的交通变得非常的堵塞。Rin只能通过没有被堵死的街道通行,去品尝所在建筑物的拉面。
现在Rin想知道,如果她正在编号为x的建筑物,那么在从市中心到x的所有简单路径经过的街道都被堵死的情况下,Rin可以品尝到的拉面中(注意没有出现的拉面是不能算在里面的):
- 油腻程度≤y且品尝次数为奇数次的拉面有多少种?
- 油腻程度≤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]); }