SPOJ COT2 树上找路径上不同值的个数
题目大意
给出多个询问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 树上找路径上不同值的个数的更多相关文章
- poj 3417 Network (LCA,路径上有值)
题意: N个点,构成一棵树.给出这棵树的结构. M条边,(a1,b1)...(am,bm),代表给树的这些点对连上边.这样就形成了有很多环的一个新"树". 现在要求你在原树中断一条 ...
- spoj COT2(树上莫队)
模板.树上莫队的分块就是按dfn分,然后区间之间转移时注意一下就好.有个图方便理解http://blog.csdn.net/thy_asdf/article/details/47377709: #in ...
- 「日常训练&知识学习」莫队算法(二):树上莫队(Count on a tree II,SPOJ COT2)
题意与分析 题意是这样的,给定一颗节点有权值的树,然后给若干个询问,每次询问让你找出一条链上有多少个不同权值. 写这题之前要参看我的三个blog:Codeforces Round #326 Div. ...
- 最短路径(给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动一步。)
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. 说明:每次只能向下或者向右移动一步. 例: 输入: [ [1,3,1], [1,5,1], [ ...
- 牛客网 桂林电子科技大学第三届ACM程序设计竞赛 D.寻找-树上LCA(树上a到b的路径上离c最近的点)
链接:https://ac.nowcoder.com/acm/contest/558/D来源:牛客网 寻找 小猫在研究树. 小猫在研究树上的距离. 给定一棵N个点的树,每条边边权为1. Q次询问,每次 ...
- 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 树上莫队算法
题意: 给出一棵\(n(n \leq 4 \times 10^4)\)个节点的树,每个节点上有个权值,和\(m(m \leq 10^5)\)个询问. 每次询问路径\(u \to v\)上有多少个权值不 ...
- 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上面这个人推导部分写 ...
随机推荐
- golang操作文件的四种方法
golang追加内容到文件末尾 字数349 阅读54 评论0 喜欢2 golang读写文件,网上很多教程了但是今天有个需求,想要把内容追加写到文件末尾google了好久,没有查到研究了一会儿file库 ...
- Bootstrap列表
一.HTML的列表 在HTML文档中,列表结构主要有三种:有序列表.无序列表和定义列表.具体使用的标签说明如下: 1.无序列表 <ul> <li>…</li> &l ...
- Bootstrap强调内容
在实际项目中,对于一些重要的文本,希望突出强调的部分都会做另外的样式处理.Bootstrap同样对这部分做了一些轻量级的处理. 如果想让一个段落p突出显示,可以通过添加类名“.lead”实现,其作用就 ...
- 转!!java中Object转String
Object转为String的几种形式 在java项目的实际开发和应用中,常常需要用到将对象转为String这一基本功能.本文将对常用的转换方法进行一个总结.常用的方法有Object.toString ...
- hiho1123_好配对
题目 给定两个序列a和b,每个序列中可能含有重复的数字. 一个配对(i,j)是一个好配对当从第一个序列中选出一个数ai,再从第二个序列中选出一个数bj且满足ai>bj. 给出两个序列,问存在多少 ...
- 如何设置session过期时间为30分钟
今天在我的微博(Laruence)上发出一个问题: 我在面试的时候, 经常会问一个问题: “如何设置一个30分钟过期的Session?”, 大家不要觉得看似简单, 这里面包含的知识挺多, 特别适合考察 ...
- Windows CPU占用率过高
今天调试程序,发现Windows7的CPU占用率一直为25%左右,如下图所示.四核25%,换成单核那就是100%的占用率了! 上图进入"进程"页面,单击"CPU" ...
- struts2 token 使用说明
使用token标签的时候,Struts2会建立一个GUID(全局唯一的字符串)放在session中,并且会成为一个hidden放在form中. token拦截器会判断客户端form提交的token和s ...
- Excel中的表单控件和active控件
EXCEL中有两种控件:表单控件和active控件 表单控件是excel5和excel95开始使用的,从excel97开始,active控件开始出现 关于表单控件和active控件的区别和使用范围,网 ...
- hdu------1281 棋盘游戏(最小覆盖点)
棋盘游戏 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...