题目大意

给出多个询问u , v , 求出u-v路径上点权值不同的个数

开始做的是COT1,用主席树写过了,理解起来不难

很高兴的跑去做第二道,完全跟普通数组区间求k个不同有很大区别,完全没思路

膜拜http://www.cnblogs.com/oyking/p/4265823.html

这里利用莫队思想来做,在树上分块,尽可能让相连部分作为一个联通块,那么就在dfs过程中加个手写栈,如果回溯上来的时候保存的值的个数超过每块中应有的

个数那么就将他们分到同一个id块

排序也是跟普通莫队上一样,按分块编号排序,这里有两个端点,那么就先将编号小的摆在前面在排序

离线排序做好了,剩下就是转移的问题,从当前一条路径转移到下一条,diff保存了之前记录的路径上不同点的个数

之前是u,v , 现在去curu , curv , 那么先找到u-curu路径上的点,添加进来,v-curv路径上的点添加进来

画个图可以看出这是原来的路径基础上不需要的点会被再多访问一次,那些需要的点要么本身在原基础上不再访问,要么又多访问两次保持不变,像异或一样

所以记录当前点有没有被访问奇数次就行了,多访问就翻转

最后会有多余的点没有被访问到,就是LCA(u,v) LCA(curu , curv) , 这个要在访问一次即可

这里因为是分块的,所以跑的是曼哈顿距离的询问区间,不会超时

 #include <bits/stdc++.h>
using namespace std; #define N 40010
int first[N] , k;
int block[N] , sz;//对应分到的块的编号和每块应含的大小
int _stack[N] , top , cursz , ID;//手写栈
int n , m;
int hash[N] , a[N] , b[N]; struct Edge{
int x , y , next;
Edge(){}
Edge(int x , int y , int next):x(x),y(y),next(next){}
}e[N<<]; void add_edge(int x , int y)
{
e[k] = Edge(x , y , first[x]);
first[x] = k++;
} int dp[N<<][] , id[N<<] , dep[N<<] , No[N] , fa[N] , dfs_clock;
int depth[N]; void add_block(int &cursz , int ID)
{
while(cursz){
block[_stack[--top]] = ID;
// cout<<"IN: "<<ID<<" "<<_stack[top]<<" "<<top<<" "<<sz<<endl;
cursz--;
}
} void dfs(int u , int f , int d)
{
id[++dfs_clock] = u , No[u] = dfs_clock , dep[dfs_clock] = d;
fa[u] = f , depth[u] = d;
for(int i=first[u] ; ~i ; i=e[i].next){
int v = e[i].y;
if(v == f) continue;
dfs(v , u , d+);
id[++dfs_clock] = u , dep[dfs_clock] = d;
}
//树上分块重要部分
cursz++;
_stack[top++] = u;
if(cursz>=sz) add_block(cursz , ++ID);
} void ST(int n)
{
for(int i= ; i<=n ; i++) dp[i][] = i;
for(int j= ; (<<j)<=n ; j++){
for(int i= ; i+(<<j)-<=n ; i++){
int a = dp[i][j-] , b=dp[i+(<<(j-))][j-];
dp[i][j] = dep[a]<dep[b]?a:b;
}
}
} int RMQ(int l , int r)
{
int k=;
while((<<(k+))<=r-l+) k++;
int a = dp[l][k] , b = dp[r-(<<k)+][k];
return dep[a]<dep[b]?a:b;
} int LCA(int u , int v)
{
int x=No[u] , y=No[v];
if(x>y) swap(x , y);
return id[RMQ(x,y)];
} void get_hash(int n){
for(int i= ; i<=n ; i++)
hash[i] = lower_bound(b+ , b+n+ , a[i])-b;
} struct Query{
int u , v , id;
void reset(){
if(block[u]>block[v]) swap(u , v);
}
bool operator<(const Query &m) const{
return block[u]<block[m.u]||(block[u]==block[m.u] && block[v]<block[m.v]);
}
void in(int i){scanf("%d%d" , &u , &v);id=i;}
}qu[]; int ans[] , vis[N] , cnt[N] , diff; void xorNode(int x)
{
// cout<<"xor: "<<x<<endl;
if(vis[x]) vis[x]=false , diff -= (--cnt[hash[x]]==);
else vis[x] = true , diff += (++cnt[hash[x]]==);
} void xorPath(int x , int y)
{
// cout<<"path: "<<x<<" "<<y<<endl;
if(depth[x]<depth[y]) swap(x , y);
while(depth[x]>depth[y]){
xorNode(x);
x = fa[x];
}
while(x!=y){
xorNode(x) , xorNode(y);
x = fa[x] , y=fa[y];
}
} void debug()
{
// for(int i=1 ; i<=n ; i++) cout<<"i: "<<block[i]<<" "<<hash[i]<<" fa: "<<fa[i]<<" "<<depth[i]<<endl;
cout<<"test: "<<LCA(,)<<" "<<LCA( , )<<endl;
}
void solve()
{
sz = (int)sqrt(n+0.5);
dfs( , , );
ST(n*-);
add_block(cursz , ++ID);
// debug();
for(int i= ; i<m ; i++){
qu[i].in(i);
qu[i].reset();
}
sort(qu , qu+m);
memset(vis , , sizeof(vis));
diff = ;
int curu= , curv=;
xorNode();
for(int i= ; i<m ; i++){
xorPath(curu , qu[i].u);
xorPath(curv , qu[i].v);
xorNode(LCA(curu , curv));
xorNode(LCA(qu[i].u , qu[i].v));
curu = qu[i].u , curv = qu[i].v;
ans[qu[i].id] = diff;
// cout<<"----华丽的分割线---"<<endl;
}
for(int i= ; i<m ; i++) printf("%d\n" , ans[i]);
} int main()
{
// freopen("in.txt" , "r" , stdin);
scanf("%d%d" , &n , &m);
for(int i= ; i<=n ; i++) scanf("%d" , &a[i]) , b[i]=a[i];
sort(b+ , b+n+);
get_hash(n);
int x , y;
memset(first , - , sizeof(first));
top = cursz = ID = k = ;
for(int i= ; i<n ; i++){
scanf("%d%d" , &x , &y);
add_edge(x , y);
add_edge(y , x);
}
solve();
return ;
}

SPOJ COT2 树上找路径上不同值的个数的更多相关文章

  1. poj 3417 Network (LCA,路径上有值)

    题意: N个点,构成一棵树.给出这棵树的结构. M条边,(a1,b1)...(am,bm),代表给树的这些点对连上边.这样就形成了有很多环的一个新"树". 现在要求你在原树中断一条 ...

  2. spoj COT2(树上莫队)

    模板.树上莫队的分块就是按dfn分,然后区间之间转移时注意一下就好.有个图方便理解http://blog.csdn.net/thy_asdf/article/details/47377709: #in ...

  3. 「日常训练&知识学习」莫队算法(二):树上莫队(Count on a tree II,SPOJ COT2)

    题意与分析 题意是这样的,给定一颗节点有权值的树,然后给若干个询问,每次询问让你找出一条链上有多少个不同权值. 写这题之前要参看我的三个blog:Codeforces Round #326 Div. ...

  4. 最短路径(给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动一步。)

    给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. 说明:每次只能向下或者向右移动一步. 例: 输入: [ [1,3,1], [1,5,1], [ ...

  5. 牛客网 桂林电子科技大学第三届ACM程序设计竞赛 D.寻找-树上LCA(树上a到b的路径上离c最近的点)

    链接:https://ac.nowcoder.com/acm/contest/558/D来源:牛客网 寻找 小猫在研究树. 小猫在研究树上的距离. 给定一棵N个点的树,每条边边权为1. Q次询问,每次 ...

  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 树上莫队算法

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

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

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

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

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

随机推荐

  1. Android星星评分控件RatingBar的使用

    在Android的开发中,有一个叫做评分控件RatingBar,我们可以使用该控件做等级划分.评分等作用,星星形状显示,也可以半星级别,我们来看一下评分控件如何使用. 布局文件中定义控件以及属性,这里 ...

  2. c/c++小知识

    1.printf计算参数时是从右到左 2.(int&)a 表示把a在内存中的值强行当作int数来处理 3.float四字节,1位符号位(正数为0),8位指数位(0采取01111111),23位 ...

  3. CSS3_概述、发展史、模块介绍、与浏览器之间的关系

    一.CSS3概述和CSS3的发展史: 1.css3概述: CSS3是CSS2的升级版本,3只是版本号,它在CSS2.1的基础上增加了很多强大的新功能.    目前主流浏览器chrome.safari. ...

  4. Mvc4_ActionResult应用

    通常我们在一个ASP.NET MVC项目中创建一个Controller的时候,Index()方法默认的返回类型都是ActionResult,通过查看UML图,ActionResult实际上是一个抽象类 ...

  5. mysql优化(三)–explain分析sql语句执行效率

    mysql优化(三)–explain分析sql语句执行效率 mushu 发布于 11个月前 (06-04) 分类:Mysql 阅读(651) 评论(0) Explain命令在解决数据库性能上是第一推荐 ...

  6. 11 个用来创建图形和图表的 JavaScript 工具包

    11个用来创建图形和图表的JavaScript工具包,方便开发者使用,喜欢的各位收藏一下吧! Aristochart DEMO|| Download Aristochart 是一个用来创建图形和图表的 ...

  7. Css:背景色透明,内容不透明之终极方法!兼容所有浏览器

    转载 http://www.cnblogs.com/jikey/archive/2012/08/31/2665880.html <!DOCTYPE html PUBLIC "-//W3 ...

  8. 简述 Ruby 与 DSL 在 iOS 开发中的运用

    阅读本文不需要预先掌握 Ruby 与 DSL 相关的知识 何为 DSL DSL(Domain Specific Language) 翻译成中文就是:"领域特定语言".首先,从定义就 ...

  9. listview加载性能优化ViewHolder

    在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局, 但当listview有大量的数据需要加载的时候 ...

  10. 批次更新BAPI_OBJCL_CHANGE

    FORM frm_edit_batch TABLES pt_field STRUCTURE dfies USING ps_batch TYPE ty_batch CHANGING ps_rturn T ...