Description

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

???

看了个把小时并没有发现这是仙人掌。
先将一个环中,从1开始最先走到的的设为环顶(由仙人掌的定义显然唯一,1所在的环设1为根就行)。缩成仙人掌树
LL的高级缩法:求出low与dfn,按原顺序dfs,对于一条边(a,b),若dfn[a]<=low[b],那么a是一个割点,可以将下面的点fa设为到a.
若dfn[a]>low[b],那么b会有一条向上的边。 此时a,b应在同一个环中,所以fa[b]=fa[a]。

可以发现,查询x点的答案,就是x子树的答案。
考虑线段树合并。从下往上做,搞完这个点的询问就把它合并到父亲那里去。
合并的时间复杂度与两颗线段树公共点成线性。
但据说总时间是nlogn的,证明不详
不过观察代码可以发现。
我们不妨设想为将所有儿子都合并到第一个儿子上,当x,y都不为空时,就要继续往下做。 这时候y这个点相当于被废弃。而初始总点数不超过nlogn,因此可以发现往下做的次数不超过nlogn.因此可以认为时间复杂度就是O(nlogn) (可能会带较大常数,至少是2吧)

void merge(int &x,int y,int l,int r) {if (y==0) return;if (x==0) x=y; else {if (l==r) {int cs=T[x][1]+T[y][1];T[x][0]=T[x][1]=0; T[x][cs&1]=1;return;}merge(c[x][0],c[y][0],l,l+r>>1);merge(c[x][1],c[y][1],(l+r>>1)+1,r);update(x);}
}

因此复杂度为O(nlogn)O(nlogn)O(n log n)
这一题就开权值线段树存一下,种类x的奇贡献,偶贡献。 合并时求和,注意叶子特判即可。

Code

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int M=1.5e5+10,N=1e5+10;int to[M*2],nex[M*2],final[N],tot,d[N];
int qy[N][2],qnex[N],qfinal[N],loc[N],qtot,ans[N];
int fa[N];int n,m,q,a[N];
void link(int x,int y) {to[++tot]=y,nex[tot]=final[x],final[x]=tot;
}
int low[N],dfn[N],stm;
void form(int x) {low[x]=dfn[x]=++stm;for (int i=final[x];i;i=nex[i]) {int y=to[i]; if (!dfn[y]) {form(y);low[x]=min(low[x],low[y]);} else low[x]=min(low[x],dfn[y]);}
}
void build(int x) {for (int i=final[x]; i; i=nex[i]) {int y=to[i]; if (dfn[y]>dfn[x] && fa[y]==0) {if (dfn[x]<=low[y]) fa[y]=x,d[x]++; else fa[y]=fa[x],d[fa[x]]++;build(y);}}
}
int qu,Q[N],L,R,T[2700000][2],c[2700000][2],fft,root[N],mx;
void update(int x) {T[x][0]=T[c[x][0]][0]+T[c[x][1]][0];T[x][1]=T[c[x][0]][1]+T[c[x][1]][1];
}
void query(int x,int l,int r,int qw,int qloc,int &sum) {if (!x || l>qloc) return;if (r<=qloc) {sum+=T[x][qw];return;}query(c[x][0],l,l+r>>1,qw,qloc,sum);query(c[x][1],(l+r>>1)+1,r,qw,qloc,sum);
}void merge(int &x,int y,int l,int r) {if (y==0) return;if (x==0) x=y; else {if (l==r) {int cs=T[x][1]+T[y][1];T[x][0]=T[x][1]=0; T[x][cs&1]=1;return;}merge(c[x][0],c[y][0],l,l+r>>1);merge(c[x][1],c[y][1],(l+r>>1)+1,r);update(x);}
}
void change(int &x,int l,int r,int tg) {if (x==0) x=++fft;if (l==r) {if (T[x][0]+T[x][1]==0) T[x][1]=1;else T[x][0]^=1,T[x][1]^=1;return;}if (tg<=(l+r>>1)) change(c[x][0],l,l+r>>1,tg);else change(c[x][1],(l+r>>1)+1,r,tg);update(x);
}int main() {freopen("map.in","r",stdin);freopen("map.out","w",stdout);cin>>n>>m;for (int i=1; i<=n; i++) scanf("%d",&a[i]),mx=max(a[i],mx);for (int i=1; i<=m; i++) {int x,y; scanf("%d %d",&x,&y); link(x,y),link(y,x);}cin>>qu;for (int i=1; i<=qu; i++) {int ty,x,y; scanf("%d %d %d",&ty,&x,&y);qy[++qtot][0]=ty,qy[qtot][1]=y;qnex[qtot]=qfinal[x]; qfinal[x]=qtot; loc[qtot]=i;}form(1);build(1);for (int i=1; i<=n; i++) if (d[i]==0) Q[++R]=i;while (L<R) { int x=Q[++L];change(root[x],1,mx,a[x]);for (int i=qfinal[x];i;i=qnex[i]) {query(root[x],1,mx,qy[i][0],qy[i][1],ans[loc[i]]);}if (fa[x]) merge(root[fa[x]],root[x],1,mx);if (x && --d[fa[x]]==0) Q[++R]=fa[x];}for (int i=1; i<=qu; i++) printf("%d\n",ans[i]);
}

jzoj5629 【NOI2018模拟4.4】Map (业界毒瘤仙人掌缩环,线段树合并)相关推荐

  1. BZOJ5419[Noi2018]情报中心——线段树合并+虚树+树形DP

    题目链接: [NOI2018]情报中心 题目大意:给出一棵n个节点的树,边有非负边权,并给出m条链,对于每条链有一个代价,要求选出两条有公共边的链使两条链的并的边权和-两条链的代价和最大. 花了一天的 ...

  2. UOJ #395 BZOJ 5417 Luogu P4770 [NOI2018]你的名字 (后缀自动机、线段树合并)

    NOI2019考前做NOI2018题.. 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=5417 (luogu) http ...

  3. [2021.1.27多校省选模拟10]跑步(线段树合并)

    [2021.1.27多校省选模拟10]跑步 经典的树上启发式合并题目,维护对应子树的从当前点到子树内一个节点这个链待定,其他部分已经确定的方案数,这个东西按照对应点到根节点的路径点权和为下标存在一个权 ...

  4. 【NOI模拟赛】最小生成树(kruskal算法,线段树合并)

    题面 (一道原创题,我直接扒图了 时限:2s,空间:1GB 题解 为了方便,下文认为 n , m , q n,m,q n,m,q 同阶.同样,不妨给每条边强制定大小,使得不存在两条边边权相等. 有一个 ...

  5. 业界毒瘤仙人掌一条龙服务

    本slide是为了NJU集训队准备....未完待续... 正经定义 : 无向图中的每条边至多位于一个简单环上,且任意两点可达. 由此可知仙人掌的构造方式很"优美",即生成一棵树,把 ...

  6. 【NOI2018】你的名字【后缀自动机】【可持久化线段树合并】【乱搞】

    题意:给一个串 SSS,qqq 次询问,每次给定串 TTT 和 l,rl,rl,r ,求有多少个本质不同的串是 TTT 的子串而不是 Sl-rS_{l\dots r}Sl-r​ 的子串. ∣S∣≤5× ...

  7. jzoj5365-[GDOI2018模拟9.14]通信【线段树合并】

    正题 题目大意 nnn个节点的一棵树,随机选择一个区间,求这个区间的点所构成的虚树的期望权值和. 解题思路 考虑每一条边的贡献,定义一边的点为黑点,一边的为白点,显然包含黑白的区间都会产生贡献.考虑减 ...

  8. jzoj3338-[NOI2013模拟]法法塔的奖励【权值线段树,线段树合并】

    正题 题目大意 一棵树,对于每个点,求从任何一个在该点的子树为头,以该点为结尾的序列必须选择这个点的最长不降子序列. 解题思路 首先我们使用权值线段树计算答案每个点(l,r,w)(l,r,w)(l,r ...

  9. [CSP-S模拟测试]:影魔(树状数组+线段树合并)

    题目背景 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万. 千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄. 每一个灵魂,都有着 ...

最新文章

  1. jQuery DOM
  2. 伊利诺伊香槟分校计算机科学,伊利诺伊大学香槟分校计算机科学与工程世界排名2019年最新排名第24(ARWU世界排名)...
  3. C 多线程的互斥锁应用RAII机制
  4. canvas绘制渐变
  5. yolov5-detect.py解析与重写
  6. C# 解析 Json数据
  7. 手把手玩转win8开发系列课程(20)
  8. 20172329《程序设计与数据结构》实验一:线性结构实验报告
  9. windows下shell工具cygwin
  10. 毕业生写论文必备!!超详细讲解参考文献格式
  11. JFLASH添加华大型号详细教程
  12. CDISC SDTM AE domain学习笔记 - 2
  13. LOJ 6437 PKUSC2018 PKUSC
  14. 资产配置那些事-标准普尔家庭资产象限图
  15. 6个优秀的图片素材网站,全部免费
  16. 在线教育:直播授课在这三个阶段有哪些要看的?
  17. jQuery 操作 input 之 checkbox
  18. 人人贷等平台都在推的打折债转,背后有何玄机?
  19. 大数据入门的4个必备常识
  20. 软件测试面试题:请设计一个关于ATM自动取款机的测试用例?

热门文章

  1. python应用内部审计_软件机器人实现内部审计自动化变革,助力企业转型数字化审计...
  2. AMD显卡性能测试软件,谁更适合Win7?AMD与NVIDIA显卡性能对比
  3. 一起来学 R编程吧(2)---判断语句switch函数的用法
  4. 集合--List集合练习--集合的嵌套、Random类获取随机数
  5. 新手教程篇-阿里云账号如何注册?
  6. Word插入Latex公式的几种方式~(TeXsWord、EqualX、Aurora、向Office插入LaTeX公式的工具)...
  7. semi-suppervised learning 半监督学习
  8. 数据链路层概述(主要解决的三个问题)
  9. 公历转农历C/C++代码
  10. 佐切的第一天学习分享