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

思路:树上莫队的模板题

LCA用tarjan算法来找,可以变成DFS以后的序列,然后再用莫队算法的思路。

#include <bits/stdc++.h>

using namespace std;
int const SIZE=40100;
int const BLOCK_SIZE=300; //利用hash记录LCA
struct Hash{
typedef struct __t{int a;int b;__t(int aa=0,int bb=0):a(aa),b(bb){}}key_t;
typedef int value_t;
enum{MOD=0x1fffff};
key_t keys[MOD+1];
value_t values[MOD+1]; int head[MOD+1];
int next[MOD+1];
int toUsed; Hash():toUsed(0){fill(head,head+MOD+1,-1);} void clear(){fill(head,head+MOD+1,-1);toUsed=0;} int getKey(key_t const&key)const {
int ret=17;
ret=ret*37+key.a;
ret=ret*37+key.b;
return ret;
} void insert(key_t const&key,value_t const&value){
int k = getKey(key) & MOD;
keys[toUsed] = key;
values[toUsed] = value;
next[toUsed] = head[k];
head[k] = toUsed++;
} value_t find(key_t const&key)const{
int k = getKey(key) & MOD;
for(int i=head[k];i!=-1;i=next[i]){
if ( keys[i].a == key.a && keys[i].b == key.b ) return values[i];
}
return 0;
} void disp(FILE*fp)const{
for(int i=1;i<toUsed;++i){
fprintf(fp,"(%d %d): %d\n",keys[i].a,keys[i].b,values[i]);
}
}
}Lca; struct dege_t{
int to;
int next;
}Edge[SIZE<<1]; int ECnt=1;
int Vertex[SIZE]={0}; inline void makeEdge(int a,int b)
{
Edge[ECnt].to=b;
Edge[ECnt].next=Vertex[a];
Vertex[a]=ECnt++; Edge[ECnt].to=a;
Edge[ECnt].next=Vertex[b];
Vertex[b]=ECnt++;
} //生成DFS序
int InIdx[SIZE],OutIdx[SIZE];
int NewIdx[SIZE<<1];
int NCnt = 1;
void dfs(int node,int parent){
NewIdx[NCnt] = node;
InIdx[node] = NCnt++;
for(int next=Vertex[node];next;next=Edge[next].next){
int to = Edge[next].to;
if ( to != parent ) dfs(to,node);
}
NewIdx[NCnt] = node;
OutIdx[node] = NCnt++;
} //Tarjan算法中用到的并查集
int Father[SIZE];
int find(int x){return x==Father[x]?x:Father[x]=find(Father[x]);} bool Flag[SIZE] = {false};
vector<vector<int> > Questions(SIZE,vector<int>()); //Tarjan算法一次性求出所有的LCA
void Tarjan(int u,int parent){
Father[u] = u;
Flag[u] = true; for(int next=Vertex[u];next;next=Edge[next].next){
int to = Edge[next].to;
if ( to == parent ) continue;
Tarjan(to,u);
Father[to] = u;
} vector<int>&vec=Questions[u];
for(vector<int>::iterator it=vec.begin();it!=vec.end();++it){
int v = *it;
if ( Flag[v] ){
int r = find(v);
Lca.insert(Hash::key_t(u,v),r);
Lca.insert(Hash::key_t(v,u),r);
}
}
} struct _t{
int s,e;
int idx;
int lca;
}; bool operator < (_t const&lhs,_t const&rhs){
int ln = lhs.s / BLOCK_SIZE;
int rn = rhs.s / BLOCK_SIZE;
return ln < rn || ( ln == rn && lhs.e < rhs.e );
}
int N,M;
int A[SIZE];
_t B[100000]; //将原树上的路径问题转化为DFS序中的区间问题
inline void mkQuestion(int a,int b,int idx){
int lca = Lca.find(Hash::key_t(a,b));
if ( lca == a || lca == b ){
int t = lca == a ? b : a;
B[idx].s = OutIdx[t];
B[idx].e = OutIdx[lca];
B[idx].lca = 0;
}else{
B[idx].lca = lca;
if ( OutIdx[a] < InIdx[b] ) B[idx].s = OutIdx[a], B[idx].e = InIdx[b];
else B[idx].s = OutIdx[b], B[idx].e = InIdx[a];
}
} int MoAns;
int Ans[100000],Cnt[SIZE];
inline void insert(int n){
if ( 1 == ++Cnt[n] ) ++MoAns;
} inline void remove(int n){
if ( 0 == --Cnt[n] ) --MoAns;
} void MoOp(int idx){
int k = NewIdx[idx];
if ( Flag[k] ) remove(A[k]);
else insert(A[k]);
Flag[k] ^= 1;
}
void Mo(){
sort(B,B+M); fill(Flag,Flag+N+1,false);
int curLeft = 1;
int curRight = 0;
MoAns = 0; for(int i=0;i<M;++i){
while( curRight < B[i].e ) MoOp(++curRight);
while( curLeft > B[i].s ) MoOp(--curLeft);
while( curRight > B[i].e ) MoOp(curRight--);
while( curLeft < B[i].s ) MoOp(curLeft++);
if ( B[i].lca ){
Ans[B[i].idx] = MoAns + ( 0 == Cnt[A[B[i].lca]] ? 1 : 0 );
}else{
Ans[B[i].idx] = MoAns;
} }
}
void init(int n){
ECnt = NCnt = 1;
fill(Vertex,Vertex+n+1,0);
fill(Flag,Flag+n+1,false);
}
int getUnsigned(){
char ch = getchar();
while( ch > '9' || ch < '0' ) ch = getchar(); int ret = 0;
do ret = ret * 10 + (int)(ch-'0');while( '0' <= (ch=getchar()) && ch <= '9' );
return ret;
} int W[SIZE];
bool read(){
if ( EOF == scanf("%d",&N) ) return false;
M = getUnsigned(); init(N); //权值输入并离散化
for(int i=1;i<=N;++i) W[i] = A[i] = getUnsigned();
sort(W+1,W+N+1);
int* pn = unique(W+1,W+N+1);
for(int i=1;i<=N;++i) A[i] = lower_bound(W+1,pn,A[i]) - W; int a,b;
for(int i=1;i<N;++i){
a = getUnsigned();
b = getUnsigned();
makeEdge(a,b);
}
dfs(1,0); for(int i=0;i<M;++i){
B[i].s = getUnsigned();
B[i].e = getUnsigned();
B[i].idx = i;
Questions[B[i].s].push_back(B[i].e);
Questions[B[i].e].push_back(B[i].s);
} Tarjan(1,0);
for(int i=0;i<M;++i) mkQuestion(B[i].s,B[i].e,i); return true;
}
int main(){
//freopen("1.txt","r",stdin);
while ( read() ){
Mo();
for(int i=0;i<M;++i)printf("%d\n",Ans[i]);
}
return 0;
}

COT2 - Count on a tree II(树上莫队)的更多相关文章

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

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

  2. SP10707 COT2 - Count on a tree II (树上莫队)

    大概学了下树上莫队, 其实就是在欧拉序上跑莫队, 特判lca即可. #include <iostream> #include <algorithm> #include < ...

  3. SP10707 COT2 - Count on a tree II [树上莫队学习笔记]

    树上莫队就是把莫队搬到树上-利用欧拉序乱搞.. 子树自然是普通莫队轻松解决了 链上的话 只能用树上莫队了吧.. 考虑多种情况 [X=LCA(X,Y)] [Y=LCA(X,Y)] else void d ...

  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]Count on a tree II(树上莫队)

    树上莫队模板题. 使用欧拉序将树上路径转化为普通区间. 之后莫队维护即可.不要忘记特判LCA #include<iostream> #include<cstdio> #incl ...

  6. 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  ...

  7. 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 ...

  8. 【SPOJ10707】 COT2 Count on a tree II

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

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

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

随机推荐

  1. CommonTabLayout+ViewPager快速完成APP首页搭建

    款APP开始的时候往往少不了多页面的切换,这就涉及到viewpager的使用,以前往往用Google自带的效果去实现,比较麻烦不说,后面做出来的效果还不如人意. 下面就利用CommonTabLayou ...

  2. weblogic负载分发

    博客分类: weblogic 负载均衡的实现方式有很多种,这里只介绍三种相对来说成本较低的方案(维护成本以及费用成本)weblogic自带的proxy.apache.nginx 1.weblogic自 ...

  3. dhcp 过程

    The Question SuperUser reader Sagnik Sarkar wants to know what the difference between 127.0.0.1 and ...

  4. Unable to connect to database server to retrieve database list; Arcgis 连接不上postsql库;

    在C:\Program Files (x86)\ArcGIS\Desktop10.2\bin 目录下添加 pg依赖的插件 插件下载地址:

  5. VC++ error C1083 无法打开包括文件 fstream.h,iostream.h怎么办

    1 如下图所示,VS中不支持iostream.h和fstream.h的说法   2 改成下面三行就可以编译通过了 #include<iostream> #include <fstre ...

  6. vue + vue-lazyload 实现图片懒加载

    1.安装 npm i vue-lazyload -S 2.配置 main.js /***图片模板等懒加载 start ***/ import VueLazyload from 'vue-lazyloa ...

  7. cf246 ENew Reform (并查集找环)

    Berland has n cities connected by m bidirectional roads. No road connects a city to itself, and each ...

  8. MySQL基础笔记(六) 存储过程与函数

    写在开头:本文所有的示例都是基于workers表,表中保存了某公司的员工姓名.性别.工资.年龄和居住城市,如下: +----+-----------+--------+--------+------+ ...

  9. LoadRunner关联需要转义的常见字符

    转义字符总结 在做手动关联时,取边界值的时候,会经常用到转义字符,现将转义字符整理如下: \b 退格             \f 换页             \n 换行             \ ...

  10. 说说Windows7 64bits下安装TensorFlow GPU版本会遇到的一些坑

    不多说,直接上干货! 再写博文,回顾在Windows7上安装TensorFlow-GPU的一路坑 Windows7上安装TensorFlow的GPU版本后记 欢迎大家,加入我的微信公众号:大数据躺过的 ...