传送门
给定一颗无根树,求树上两点路径上的节点有多少不同的数字
可以离线

分析

前提,能够通过某种操作,将树上路径问题,转化成区间问题
这样,类似于求区间不同数,区间众数,区间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【树上莫队】相关推荐

  1. 【莫队/树上莫队/回滚莫队】原理详解及例题:小B的询问(普通莫队),Count on a tree II(树上莫队),kangaroos(回滚莫队)

    文章目录 问题引入 介绍莫队算法及其实现过程 时间复杂度 莫队算法适用范围 莫队奇偶优化 普通莫队:小B的询问 树上莫队:SP10707 COT2 - Count on a tree II 回滚莫队: ...

  2. SP10707 COT2 - Count on a tree II

    SP10707 COT2 - Count on a tree II 题意: 给定 n 个结点的树,每个结点有一种颜色. m 次询问,每次询问给出 u,v,回答 u,v 之间的路径上的结点的不同颜色数. ...

  3. [学习笔记]树上莫队

    其实树上莫队是一个欧拉序而已嘛,像普通的莫队,特判一下出现过两次的值就行了 设 \(st_i\) 为 \(i\) 进栈的时间,\(ed_i\) 为 \(i\) 出栈的时间,\(dfn_x<dfn ...

  4. 莫队算法 (普通莫队、带修莫队、树上莫队)

    莫队算法 主要基于分块的思想 用结构体记录询问的左右端点及询问编号 (这是一个离线算法) 通过排序优化指针扫描顺序优化时间复杂度 . 1.普通莫队 例题:SP3267 DQUERY - D-query ...

  5. 莫队算法(普通莫队、带修莫队、树上莫队、不删除莫队)学习笔记【理解+套路/核心代码+例题及题解】

    一.理解 我的理解就是巧妙的暴力,利用双指针以及分块思想,巧妙的移动双指针,时间复杂度可以达到O(NlogN). 强推博客:写的又好又全.链接 二.套路 1.普通莫队 [1]核心代码 bool cmp ...

  6. 【SPOJ COT2】Count on a tree II,树上莫队

    Time:2016.09.07 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 第一次写树上莫队 被char哥怒裱一通 实际上还是比较简单的 序列的相关维护问题转移到树上一般都要涉及 ...

  7. 【SPOJ】Count On A Tree II(树上莫队)

    [SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...

  8. 莫队算法二(树上莫队cot2,Haruna’s Breakfast)

    例一:不带修改 Count on a tree II Time Limit: 1207MS   Memory Limit: 1572864KB   64bit IO Format: %lld & ...

  9. 【XSY3490】线段树(广义线段树,树上莫队)

    题面 线段树 题解 本题分两 Part 走. Part 1 我们需要解决: 如何在广义线段树上快速区间定位节点. 对于有 nnn 个叶子节点.共 2n−12n-12n−1 个节点的广义线段树 AAA, ...

最新文章

  1. Crazy C Pointer
  2. xcode5 中Provisioning Profiles列表清理方法
  3. 查看mysql本地路径
  4. Coding:就地合并两个排序数组
  5. 绘制屏幕时给单选按钮分组
  6. .NET 工具生成引擎概述
  7. TechNet 晒文 - Windows 7 系列汇总
  8. mysql(一主从从)
  9. Mac电脑下的单片机开发环境配置心得
  10. HealthKit详解
  11. 国内外优秀的计算机视觉团队汇总
  12. 如何改typecho主题头像_零成本搭建hexo个人博客(二)--修改主题
  13. 【SpringBoot项目中使用Mybatis批量插入百万条数据】
  14. VB6.0 遇到“不能加载 MSCOMCTL.ocx“ 问题处理
  15. Android串口通信:串口读写
  16. 云计算已渗透大众生活,去中心化云计算发展前景广阔
  17. 自制的百度输入法皮肤
  18. 电子商务售后操作技巧
  19. 微服务架构之:Redis的分布式锁---搭建生产可用的Redis分布式锁
  20. < 开源项目框架:推荐几个开箱即用的开源管理系统 - 让开发不再复杂 >

热门文章

  1. oracle bam教程,Oracle业务活动监控(BAM)和业务规则
  2. 如何修改ftp服务器密码
  3. matlab代码规范(自用)
  4. python 抓取微博评论破亿_Python爬虫实战演练:爬取微博大V的评论数据
  5. python代码手机壁纸_爬虫 抓取王者荣耀所有英雄皮肤高清壁纸+超强注
  6. 实现安卓直播-第三方平台(暴风云视频直播)
  7. git常用操作与在gitlab上进行MergeRequest(git rebase)
  8. 程序员500字年终总结
  9. Linux是 UEFI 还是L启动模式,怎么看系统是UEFI还是Legacy BIOS启动模式
  10. 选拔赛proA:经营小卖部