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 numbered from 1 to N.Each node has an integer weight.
We will ask you to perfrom 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 ith integer denotes the weight of the ith 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.
题目大意:给一棵树,每个点有一个权值。多次询问路径(a, b)上有多少个权值不同的点。
思路:参考VFK WC 2013 糖果公园 park 题解(此题比COT2要难。)
http://vfleaking.blog.163.com/blog/static/174807634201311011201627/
代码(2.37S):
#include <bits/stdc++.h>
using namespace std; const int MAXV = ;
const int MAXE = MAXV << ;
const int MAXQ = ;
const int MLOG = ; namespace Bilibili { int head[MAXV], val[MAXV], ecnt;
int to[MAXE], next[MAXE];
int n, m; int stk[MAXV], top;
int block[MAXV], bcnt, bsize; struct Query {
int u, v, id;
void read(int i) {
id = i;
scanf("%d%d", &u, &v);
}
void adjust() {
if(block[u] > block[v]) swap(u, v);
}
bool operator < (const Query &rhs) const {
if(block[u] != block[rhs.u]) return block[u] < block[rhs.u];
return block[v] < block[rhs.v];
}
} ask[MAXQ];
int ans[MAXQ];
/// Graph
void init() {
memset(head + , -, n * sizeof(int));
ecnt = ;
} void add_edge(int u, int v) {
to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; next[ecnt] = head[v]; head[v] = ecnt++;
} void gethash(int a[], int n) {
static int tmp[MAXV];
int cnt = ;
for(int i = ; i <= n; ++i) tmp[cnt++] = a[i];
sort(tmp, tmp + cnt);
cnt = unique(tmp, tmp + cnt) - tmp;
for(int i = ; i <= n; ++i)
a[i] = lower_bound(tmp, tmp + cnt, a[i]) - tmp + ;
} void read() {
scanf("%d%d", &n, &m);
for(int i = ; i <= n; ++i) scanf("%d", &val[i]);
gethash(val, n);
init();
for(int i = , u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
add_edge(u, v);
}
for(int i = ; i < m; ++i) ask[i].read(i);
}
/// find_block
void add_block(int &cnt) {
while(cnt--) block[stk[--top]] = bcnt;
bcnt++;
cnt = ;
} void rest_block() {
while(top) block[stk[--top]] = bcnt - ;
} int dfs_block(int u, int f) {
int size = ;
for(int p = head[u]; ~p; p = next[p]) {
int v = to[p];
if(v == f) continue;
size += dfs_block(v, u);
if(size >= bsize) add_block(size);
}
stk[top++] = u;
size++;
if(size >= bsize) add_block(size);
return size;
} void init_block() {
bsize = max(, (int)sqrt(n));
dfs_block(, );
rest_block();
}
/// ask_rmq
int fa[MLOG][MAXV];
int dep[MAXV]; void dfs_lca(int u, int f, int depth) {
dep[u] = depth;
fa[][u] = f;
for(int p = head[u]; ~p; p = next[p]) {
int v = to[p];
if(v != f) dfs_lca(v, u, depth + );
}
} void init_lca() {
dfs_lca(, -, );
for(int k = ; k + < MLOG; ++k) {
for(int u = ; u <= n; ++u) {
if(fa[k][u] == -) fa[k + ][u] = -;
else fa[k + ][u] = fa[k][fa[k][u]];
}
}
} int ask_lca(int u, int v) {
if(dep[u] < dep[v]) swap(u, v);
for(int k = ; k < MLOG; ++k) {
if((dep[u] - dep[v]) & ( << k)) u = fa[k][u];
}
if(u == v) return u;
for(int k = MLOG - ; k >= ; --k) {
if(fa[k][u] != fa[k][v])
u = fa[k][u], v = fa[k][v];
}
return fa[][u];
}
/// modui
bool vis[MAXV];
int diff, cnt[MAXV]; void xorNode(int u) {
if(vis[u]) vis[u] = false, diff -= (--cnt[val[u]] == );
else vis[u] = true, diff += (++cnt[val[u]] == );
} void xorPathWithoutLca(int u, int v) {
if(dep[u] < dep[v]) swap(u, v);
while(dep[u] != dep[v])
xorNode(u), u = fa[][u];
while(u != v)
xorNode(u), u = fa[][u],
xorNode(v), v = fa[][v];
} void moveNode(int u, int v, int taru, int tarv) {
xorPathWithoutLca(u, taru);
xorPathWithoutLca(v, tarv);
//printf("debug %d %d\n", ask_lca(u, v), ask_lca(taru, tarv));
xorNode(ask_lca(u, v));
xorNode(ask_lca(taru, tarv));
} void make_ans() {
for(int i = ; i < m; ++i) ask[i].adjust();
sort(ask, ask + m);
int nowu = , nowv = ; xorNode();
for(int i = ; i < m; ++i) {
moveNode(nowu, nowv, ask[i].u, ask[i].v);
ans[ask[i].id] = diff;
nowu = ask[i].u, nowv = ask[i].v;
}
} void print_ans() {
for(int i = ; i < m; ++i)
printf("%d\n", ans[i]);
} void solve() {
read();
init_block();
init_lca();
make_ans();
print_ans();
} }; int main() {
Bilibili::solve();
}
SPOJ COT2 Count on a tree II(树上莫队)的更多相关文章
- spoj COT2 - Count on a tree II 树上莫队
题目链接 http://codeforces.com/blog/entry/43230树上莫队从这里学的, 受益匪浅.. #include <iostream> #include < ...
- SPOJ COT2 Count on a tree II 树上莫队算法
题意: 给出一棵\(n(n \leq 4 \times 10^4)\)个节点的树,每个节点上有个权值,和\(m(m \leq 10^5)\)个询问. 每次询问路径\(u \to v\)上有多少个权值不 ...
- SP10707 COT2 - Count on a tree II (树上莫队)
大概学了下树上莫队, 其实就是在欧拉序上跑莫队, 特判lca即可. #include <iostream> #include <algorithm> #include < ...
- SP10707 COT2 - Count on a tree II [树上莫队学习笔记]
树上莫队就是把莫队搬到树上-利用欧拉序乱搞.. 子树自然是普通莫队轻松解决了 链上的话 只能用树上莫队了吧.. 考虑多种情况 [X=LCA(X,Y)] [Y=LCA(X,Y)] else void d ...
- [SPOJ]Count on a tree II(树上莫队)
树上莫队模板题. 使用欧拉序将树上路径转化为普通区间. 之后莫队维护即可.不要忘记特判LCA #include<iostream> #include<cstdio> #incl ...
- SPOJ COT2 - Count on a tree II(LCA+离散化+树上莫队)
COT2 - Count on a tree II #tree You are given a tree with N nodes. The tree nodes are numbered from ...
- 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 ...
- SPOJ COT2 Count on a tree II (树上莫队,倍增算法求LCA)
题意:给一个树图,每个点的点权(比如颜色编号),m个询问,每个询问是一个区间[a,b],图中两点之间唯一路径上有多少个不同点权(即多少种颜色).n<40000,m<100000. 思路:无 ...
- SPOJ COT2 Count on a tree II (树上莫队)
题目链接:http://www.spoj.com/problems/COT2/ 参考博客:http://www.cnblogs.com/xcw0754/p/4763804.html上面这个人推导部分写 ...
随机推荐
- 如何离线安装chrome插件【转】
http://blog.csdn.net/shuideyidi/article/details/45674601 原文链接 前言------可以不看: 实习做web,要弄单点登录SSO和验证Contr ...
- docker nexus oss
docker login/search x.x.x.x:8081 sonatype/docker-nexus Docker images for Sonatype Nexus with the Ora ...
- 为mutable类型的容器(array,set等)添加kvo,有点麻烦,供参考和了解下吧
http://blog.csdn.net/caryaliu/article/details/49284185 需要在被观察的属性所在的类里面实现一些方法,对开发者不友好,一般不建议使用,这里mark一 ...
- 使用C++还是QML
本质上,Qt 是一个C++类库.在引入 QML 以前,所有的开发都是基于 C++ 的,但到了 Qt 5,QML 和 Qt Quick 成为了 Qt 的核心之一,导致很多初学者在犹豫是否还需要学习 C+ ...
- 移动设备优先viewport
Bootstrap 3 的设计目标是移动设备优先,然后才是桌面设备.这实际上是一个非常及时的转变,因为现在越来越多的用户使用移动设备. 为了让 Bootstrap 开发的网站对移动设备友好,确保适当的 ...
- sphinx续5-主索引增量索引和实时索引
原文件地址:http://blog.itpub.net/29806344/viewspace-1400942/ 在数据库数据非常庞大的时候,而且实时有新的数据插入,如果我们不更新索引,新的数据就sea ...
- 正则表达式lastIndex属性浅析
有这样一段代码: var newDateStr = " 11 13:48:18"; var reg = new RegExp("[0-9]+","g& ...
- 实现 UISegmentControl 与 UIScrollView的上下级联(分别在相应的方法中加入级联代码)
实现 UISegmentControl 与 UIScrollView的上下级联,需要在 [segmentCtr addTarget:self action:@selector(segmentedCon ...
- Fiddler-001-抓包工具初识
Fiddler 是一个非常简单的网络调试器,也是目前最常用的http抓包工具之一 .通过 Fiddler,我们能够能够记录客户端和服务器之间的所有 HTTP请求,即记录并检查所有你的电脑和互联网之间的 ...
- Java学习-024-获取当前类名或方法名二三文
今天,看朋友编写程序,打印日志时,需要记录当前类的类名以及当前方法的方法名,我发现 TA 将类名或者方法名直接写死在了代码中...虽说这样可以实现记录类名和方法名,但是当有特殊情况需要修改类名或者方法 ...