SP10707 COT2 - Count on a tree II【树上莫队】
传送门
给定一颗无根树,求树上两点路径上的节点有多少不同的数字
可以离线
分析
前提,能够通过某种操作,将树上路径问题,转化成区间问题
这样,类似于求区间不同数,区间众数,区间mex等操作就能通过莫队离线来做了
这里采用 欧拉序(相关性质介绍) 进行求解,将树链问题转化成区间问题
这里注意,欧拉序求解的过程中,需要统计路径上的不同数,同时还要统计lcalcalca的值,且,如果某个节点出现了偶数次,意味着不是链上的点,所以需要去掉偶数次的点
代码
//SP10707
/*@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;int arr[MAX_N];
int uniarr[MAX_N];
int unicnt = 0;int head[MAX_N];
int tot = 0;
struct Edge {int to, nxt;
}edge[MAX_N];void addEdge(int u, int v) {edge[tot].nxt = head[u];edge[tot].to = v;head[u] = tot++;edge[tot].nxt = head[v];edge[tot].to = u;head[v] = tot++;
}int dep[MAX_N];
int father[MAX_N][21];
int dfn[MAX_N];
int out[MAX_N];
int sa[MAX_N];
int indx = 0;void dfs(int u, int from) {dfn[u] = ++indx;sa[indx] = u;father[u][0] = from;dep[u] = dep[from] + 1;for (int i = 1; i <= 20; ++i) {father[u][i] = father[father[u][i-1]][i-1];}int v;for (int i = head[u];~i;i=edge[i].nxt) {if ((v=edge[i].to) == from) continue;dfs(v, u);}out[u] = ++indx;sa[indx] = u;
}int LCA(int x, int y) {if (dep[x] > dep[y]) swap(x, y);for (int i = 20; i+1; --i) {if (dep[father[y][i]] >= dep[x]) y = father[y][i];}if (x == y) return x;for (int i = 20; i+1; --i) {if (father[x][i] != father[y][i]) {x = father[x][i];y = father[y][i];}}return father[x][0];
}int block = 1;int idb(int x) {return x / block;
}struct Qr {int l, r, lca, id;bool operator < (const Qr& B) const {return idb(l) ^ idb(B.l) ? l < B.l : (idb(l) & 1) ? r < B.r : r > B.r;}
}qr[MAX_N];Qr pre(int x, int y) {Qr res;if (dfn[x] > dfn[y]) swap(x, y);int lca = LCA(x, y);if (x != lca) {res.l = out[x];res.lca = lca;} else {res.l = dfn[x];res.lca = 0;}res.r = dfn[y];return res;
}int ans[MAX_N];
int cnt[MAX_N];
int mo = 0;
bool vis[MAX_N];void add(int x) {if (cnt[arr[x]]++);else ++mo;
}void del(int x) {if (--cnt[arr[x]]);else --mo;
}void go(int x) {x = sa[x];if (vis[x]) {del(x);} else {add(x);}vis[x] ^= 1;
}int check(int x) {if (!x) return mo;if (cnt[arr[x]]) return mo;else return mo + 1;
}void init() {memset(head, -1, sizeof head);memset(ans, 0, sizeof ans);memset(vis, 0, sizeof vis);memset(cnt, 0, sizeof vis);indx = 0;mo = 0;tot = 0;
}void solve(){init();sc("%lld%lld", &N, &M);block = max(sqrt(2*N*2*N/M), 1.1);for (int i = 1; i <= N; ++i) {sc("%lld", &arr[i]);uniarr[i] = arr[i];}unicnt = N;int u, v;for (int i = 2; i <= N; ++i) {sc("%lld%lld", &u, &v);addEdge(u, v);}dfs(1, 1);for (int i = 1; i <= M; ++i) {sc("%lld%lld", &u, &v);qr[i] = pre(u, v);qr[i].id = i;}sort(qr+1, qr+1+M);sort(uniarr+1, uniarr+1+unicnt);unicnt = unique(uniarr+1, uniarr+1+unicnt) - uniarr - 1;for (int i = 1; i <= N; ++i) {arr[i] = lower_bound(uniarr+1, uniarr+1+unicnt, arr[i]) - uniarr;}int l = 1, r = 0;for (int i = 1; i <= M; ++i) {while (l > qr[i].l) go(--l);while (r < qr[i].r) go(++r);while (l < qr[i].l) go(l++);while (r > qr[i].r) go(r--);ans[qr[i].id] = check(qr[i].lca);}for (int i = 1; i <= M; ++i) {pr("%lld\n", ans[i]);}
}signed main()
{#ifndef ONLINE_JUDGE//FILE_INFILE_OUT#endifint T = 1;//cin >> T;while (T--) solve();return AC;
}
SP10707 COT2 - Count on a tree II【树上莫队】相关推荐
- 【莫队/树上莫队/回滚莫队】原理详解及例题:小B的询问(普通莫队),Count on a tree II(树上莫队),kangaroos(回滚莫队)
文章目录 问题引入 介绍莫队算法及其实现过程 时间复杂度 莫队算法适用范围 莫队奇偶优化 普通莫队:小B的询问 树上莫队:SP10707 COT2 - Count on a tree II 回滚莫队: ...
- SP10707 COT2 - Count on a tree II
SP10707 COT2 - Count on a tree II 题意: 给定 n 个结点的树,每个结点有一种颜色. m 次询问,每次询问给出 u,v,回答 u,v 之间的路径上的结点的不同颜色数. ...
- [学习笔记]树上莫队
其实树上莫队是一个欧拉序而已嘛,像普通的莫队,特判一下出现过两次的值就行了 设 \(st_i\) 为 \(i\) 进栈的时间,\(ed_i\) 为 \(i\) 出栈的时间,\(dfn_x<dfn ...
- 莫队算法 (普通莫队、带修莫队、树上莫队)
莫队算法 主要基于分块的思想 用结构体记录询问的左右端点及询问编号 (这是一个离线算法) 通过排序优化指针扫描顺序优化时间复杂度 . 1.普通莫队 例题:SP3267 DQUERY - D-query ...
- 莫队算法(普通莫队、带修莫队、树上莫队、不删除莫队)学习笔记【理解+套路/核心代码+例题及题解】
一.理解 我的理解就是巧妙的暴力,利用双指针以及分块思想,巧妙的移动双指针,时间复杂度可以达到O(NlogN). 强推博客:写的又好又全.链接 二.套路 1.普通莫队 [1]核心代码 bool cmp ...
- 【SPOJ COT2】Count on a tree II,树上莫队
Time:2016.09.07 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 第一次写树上莫队 被char哥怒裱一通 实际上还是比较简单的 序列的相关维护问题转移到树上一般都要涉及 ...
- 【SPOJ】Count On A Tree II(树上莫队)
[SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...
- 莫队算法二(树上莫队cot2,Haruna’s Breakfast)
例一:不带修改 Count on a tree II Time Limit: 1207MS Memory Limit: 1572864KB 64bit IO Format: %lld & ...
- 【XSY3490】线段树(广义线段树,树上莫队)
题面 线段树 题解 本题分两 Part 走. Part 1 我们需要解决: 如何在广义线段树上快速区间定位节点. 对于有 nnn 个叶子节点.共 2n−12n-12n−1 个节点的广义线段树 AAA, ...
最新文章
- Crazy C Pointer
- xcode5 中Provisioning Profiles列表清理方法
- 查看mysql本地路径
- Coding:就地合并两个排序数组
- 绘制屏幕时给单选按钮分组
- .NET 工具生成引擎概述
- TechNet 晒文 - Windows 7 系列汇总
- mysql(一主从从)
- Mac电脑下的单片机开发环境配置心得
- HealthKit详解
- 国内外优秀的计算机视觉团队汇总
- 如何改typecho主题头像_零成本搭建hexo个人博客(二)--修改主题
- 【SpringBoot项目中使用Mybatis批量插入百万条数据】
- VB6.0 遇到“不能加载 MSCOMCTL.ocx“ 问题处理
- Android串口通信:串口读写
- 云计算已渗透大众生活,去中心化云计算发展前景广阔
- 自制的百度输入法皮肤
- 电子商务售后操作技巧
- 微服务架构之:Redis的分布式锁---搭建生产可用的Redis分布式锁
- < 开源项目框架:推荐几个开箱即用的开源管理系统 - 让开发不再复杂 >
热门文章
- oracle bam教程,Oracle业务活动监控(BAM)和业务规则
- 如何修改ftp服务器密码
- matlab代码规范(自用)
- python 抓取微博评论破亿_Python爬虫实战演练:爬取微博大V的评论数据
- python代码手机壁纸_爬虫 抓取王者荣耀所有英雄皮肤高清壁纸+超强注
- 实现安卓直播-第三方平台(暴风云视频直播)
- git常用操作与在gitlab上进行MergeRequest(git rebase)
- 程序员500字年终总结
- Linux是 UEFI 还是L启动模式,怎么看系统是UEFI还是Legacy BIOS启动模式
- 选拔赛proA:经营小卖部