COT2 - Count on a tree II

You are given a tree with N nodes. The tree nodes are numbered from 1 to N. Each node has an integer weight.

We will ask you to perform the following operation:

  • u v : ask for how many different integers that represent the weight of nodes there are on the path from u to v.

Input

In the first line there are two integers N and M. (N <= 40000, M <= 100000)

In the second line there are N integers. The i-th integer denotes the weight of the i-th node.

In the next N-1 lines, each line contains two integers u v, which describes an edge (u, v).

In the next M lines, each line contains two integers u v, which means an operation asking for how many different integers that represent the weight of nodes there are on the path from u to v.

Output

For each operation, print its result.

Example

Input:
8 2
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5
7 8
Output:
4
4

 

题目链接:SPOJ COT2

一开始不太会,看着这个人的教程写的:树上莫队,然而还是有几个地方不是很懂而且他的简洁代码跟文中的一些变量名对不上号……,但至少没百度搜到的某些题解代码写的丑

他的主要做法就是把树用稍微修改的DFS序变成序列,然后根据两种不同的情况进行判断,并且过程中要算上LCA的贡献,代码虽然写出来了但是感觉跟文中的方法有一点出入,有待理解

最后的LCA判断实际上是多出来的一个点,要还原回去,否则指针是在区间移动的只管辖区间,这个多出来的点会造成错误的影响

代码:

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 40010;
const int M = 200010;
struct edge
{
int to, nxt;
edge() {}
edge(int _to, int _nxt): to(_to), nxt(_nxt) {}
};
struct query
{
int u, v;
int lca, x;
int id, l, r, b;
bool operator<(const query &rhs)const
{
if (b != rhs.b)
return b < rhs.b;
return r < rhs.r;
}
};
edge E[N << 1];
query Q[M];
int head[N], tot; int arr[N];//values in nodes
int ver[N << 1], F[N], D[N << 1], dp[N << 1][18], ts; //for LCA
int ST[N << 1], EN[N << 1], A[N << 1], sz, unit; //for Mo's algo vector<int>vec;
int ans[M], cnt[N];
int cnode[N]; void init()
{
CLR(head, -1);
tot = 0;
ts = 0;
sz = 0;
vis.reset();
vec.clear();
CLR(ans, 0);
CLR(cnt, 0);
CLR(cnode, 0);
}
inline void add(int s, int t)
{
E[tot] = edge(t, head[s]);
head[s] = tot++;
}
void dfs(int u, int pre, int d)
{
ver[++ts] = u;
D[ts] = d;
F[u] = ts; ST[u] = ++sz;
A[sz] = u; for (int i = head[u]; ~i; i = E[i].nxt)
{
int v = E[i].to;
if (v != pre)
{
dfs(v, u, d + 1); ver[++ts] = u;
D[ts] = d;
}
} EN[u] = ++sz;
A[sz] = u;
}
void RMQ_init(int l, int r)
{
int i, j;
for (i = l; i <= r; ++i)
dp[i][0] = i;
for (j = 1; l + (1 << j) - 1 <= r; ++j)
{
for (i = l; i + (1 << j) - 1 <= r; ++i)
{
int a = dp[i][j - 1], b = dp[i + (1 << (j - 1))][j - 1];
dp[i][j] = D[a] < D[b] ? a : b;
}
}
}
int LCA(int u, int v)
{
int l = F[u], r = F[v];
if (l > r)
swap(l, r);
int k = log2(r - l + 1);
int a = dp[l][k], b = dp[r - (1 << k) + 1][k];
return D[a] < D[b] ? ver[a] : ver[b];
}
inline void Add(const int &u,int &Ans)
{
++cnode[u];
if (cnode[u] == 1)
{
if (++cnt[arr[u]] == 1)
++Ans;
}
else if (cnode[u] == 2)
{
if (--cnt[arr[u]] == 0)
--Ans;
}
}
inline void Del(const int &u, int &Ans)
{
--cnode[u];
if (cnode[u] == 0)
{
if (--cnt[arr[u]] == 0)
--Ans;
}
else if (cnode[u] == 1)
{
if (++cnt[arr[u]] == 1)
++Ans;
}
}
int main(void)
{
int n, m, i;
while (~scanf("%d%d", &n, &m))
{
init();
for (i = 1; i <= n; ++i)
{
scanf("%d", &arr[i]);
vec.push_back(arr[i]);
} sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
for (i = 1; i <= n; ++i)
arr[i] = lower_bound(vec.begin(), vec.end(), arr[i]) - vec.begin() + 1; for (i = 1; i < n; ++i)
{
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
dfs(1, -1, 0);
unit = sqrt(sz);
RMQ_init(1, ts);
for (i = 0; i < m; ++i)
{
scanf("%d%d", &Q[i].u, &Q[i].v);
Q[i].id = i;
Q[i].lca = LCA(Q[i].u, Q[i].v); if (ST[Q[i].u] > ST[Q[i].v])
swap(Q[i].u, Q[i].v);
if (Q[i].lca == Q[i].u)
{
Q[i].l = ST[Q[i].u];
Q[i].r = ST[Q[i].v];
Q[i].x = 0;
}
else
{
Q[i].l = EN[Q[i].u];
Q[i].r = ST[Q[i].v];
Q[i].x = 1;
}
Q[i].b = Q[i].l / unit;
}
sort(Q, Q + m);
int L = Q[0].l, R = L - 1;
int Ans = 0;
for (i = 0; i < m; ++i)
{
while (L > Q[i].l)
Add(A[--L], Ans); while (L < Q[i].l)
Del(A[L++], Ans); while (R > Q[i].r)
Del(A[R--], Ans); while (R < Q[i].r)
Add(A[++R], Ans); if (Q[i].x)
Add(Q[i].lca, Ans); ans[Q[i].id] = Ans; if (Q[i].x)
Del(Q[i].lca, Ans);
}
for (i = 0; i < m; ++i)
printf("%d\n", ans[i]);
}
return 0;
}

SPOJ COT2 - Count on a tree II(LCA+离散化+树上莫队)的更多相关文章

  1. spoj COT2 - Count on a tree II

    COT2 - Count on a tree II http://www.spoj.com/problems/COT2/ #tree You are given a tree with N nodes ...

  2. SPOJ COT2 Count on a tree II (树上莫队,倍增算法求LCA)

    题意:给一个树图,每个点的点权(比如颜色编号),m个询问,每个询问是一个区间[a,b],图中两点之间唯一路径上有多少个不同点权(即多少种颜色).n<40000,m<100000. 思路:无 ...

  3. spoj COT2 - Count on a tree II 树上莫队

    题目链接 http://codeforces.com/blog/entry/43230树上莫队从这里学的,  受益匪浅.. #include <iostream> #include < ...

  4. SPOJ COT2 Count on a tree II 树上莫队算法

    题意: 给出一棵\(n(n \leq 4 \times 10^4)\)个节点的树,每个节点上有个权值,和\(m(m \leq 10^5)\)个询问. 每次询问路径\(u \to v\)上有多少个权值不 ...

  5. SPOJ COT2 Count on a tree II (树上莫队)

    题目链接:http://www.spoj.com/problems/COT2/ 参考博客:http://www.cnblogs.com/xcw0754/p/4763804.html上面这个人推导部分写 ...

  6. SPOJ COT2 Count on a tree II(树上莫队)

    题目链接:http://www.spoj.com/problems/COT2/ You are given a tree with N nodes.The tree nodes are numbere ...

  7. 【SPOJ10707】 COT2 Count on a tree II

    SPOJ10707 COT2 Count on a tree II Solution 我会强制在线版本! Solution戳这里 代码实现 #include<stdio.h> #inclu ...

  8. 【BZOJ2589】 Spoj 10707 Count on a tree II

    BZOJ2589 Spoj 10707 Count on a tree II Solution 吐槽:这道题目简直...丧心病狂 如果没有强制在线不就是树上莫队入门题? 如果加了强制在线怎么做? 考虑 ...

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

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

随机推荐

  1. Linux一键脚本合集vps

    首先,想说说一键脚本流行的原因何在? 众所周知的是,Linux 是占据大半壁江山的服务器系统,但在桌面上的占有率可就远不是那么回事儿了,使用和熟悉 Linux 的人远没有 Windows 多,但又因为 ...

  2. Luogu P1471 方差

    题目传送门 开了十倍空间才过是什么鬼?该不会我线段树炸了吧-- 细思极恐 平均数都会求,维护区间和,到时候除一下就好了. 方差的求法如下 (用的Luogu的图片) 因为要维护一个平方,我们可以考虑使用 ...

  3. 一些常用的集合工具的代码块(缓慢更新XD,更新了多属性过滤:) )

    更新记录 虽然经常放鸽子,但是还是要记录一下更新 2017.8.30 更新了listToMap的方法,现在可以指定多个属性进行分组了,例如你要指定一个学生集合,按照名字和年龄相同的放在一组,现在只要调 ...

  4. 【6.20校内test】

    反正考的不是很好吧,赶脚炸了啊qwq 然后这两天一直在忙一些神奇的事情,所以没有整理完 手动@water_lift T1:大美江湖: [题目背景] 细雪飘落长街,枫叶红透又一年 不只为故友流连,其实我 ...

  5. 绑定Ligerui中的ligerComboBox二级联动

    $.ajax({ url: "HRHandler.ashx", data: "bz=getDepartData", cache: false, type: &q ...

  6. windows下编辑器Emacs的安装与配置

    一年成为Emacs高手(像神一样使用编辑器) http://blog.csdn.net/redguardtoo/article/details/7222501   原创作品,允许转载,转载时请务必以超 ...

  7. c++中的结构化语句 判断语句if 分支语句switch 循环语句 while 和 do while 循环语句for的使用

    作业1: 使用if语句,根据1~7的数字,输出今天是星期几?的程序. 方法一,直接使用单独的if语句 #include <iostream> using namespace std; in ...

  8. Mysql--数据操作语言(DML)

    定义:数据操作语言主要实现对数据库表中的数据进行操作,主要包括插入(insert).更新(update).删除(delete).查询(select),本节主要介绍增删改. 数据准备: 一.数据的插入( ...

  9. WebSocket 详解

    WebSocket 出现前 构建网络应用的过程中,我们经常需要与服务器进行持续的通讯以保持双方信息的同步.通常这种持久通讯在不刷新页面的情况下进行,消耗一定的内存资源常驻后台,并且对于用户不可见.在 ...

  10. Foxmail登录不了网易企业邮箱解决办法

    关于Foxmail登录不了网易企业邮箱问题 解决办法是:在设置账号的时候手动设置pop服务器和smtp服务器. 新建账号的图: 点击“手动设置”出现如下界面: 设置完成后问题解决.下面的两个是正确的, ...