题意:给一棵带点权的树,多次询问两点间路径上的不同权值数

学习了一下莫队上树(雾

先求出栈入栈序$p_{1\cdots 2n}$,记$st_x$为$x$在$p$中第一次出现的位置,$ed_x$为$x$在$p$中最后一次出现的位置

对于一个询问$(x,y)$,先令$st_x\lt st_y$,求出其$lca$,若$x=lca$,则询问$[st_x,st_y]$,否则询问$[ed_x,st_y]$还有$lca$(因为$[ed_x,st_y]$不包含$lca$)

于是我们成功地把问题转化到序列上,普通地莫队即可

不应处理出现两次的数(因为它入栈一次,出栈一次,在路径之外)

#include<stdio.h>
#include<algorithm>
#include<map>
#include<math.h>
using namespace std;
struct ask{
	int l,r,lca,sid,qid;
}q[100010];
int to[80010],nex[80010],h[40010],dep[40010],fa[40010][16],v[40010],p[80010],st[40010],ed[40010],ti[40010],ex[40010],ans[100010],M;
map<int,int>mp;
map<int,int>::iterator it;
bool cmp(ask a,ask b){
	if(a.sid==b.sid)return a.r<b.r;
	return a.sid<b.sid;
}
void add(int a,int b){
	M++;
	to[M]=b;
	nex[M]=h[a];
	h[a]=M;
}
void dfs(int x){
	st[x]=++M;
	p[M]=x;
	for(int i=h[x];i;i=nex[i]){
		if(to[i]!=fa[x][0]){
			fa[to[i]][0]=x;
			dep[to[i]]=dep[x]+1;
			dfs(to[i]);
		}
	}
	ed[x]=++M;
	p[M]=x;
}
int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	int i;
	for(i=15;i>=0;i--){
		if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
	}
	if(x==y)return x;
	for(i=15;i>=0;i--){
		if(fa[x][i]!=fa[y][i]){
			x=fa[x][i];
			y=fa[y][i];
		}
	}
	return fa[x][0];
}
int sum;
void add(int);
void del(int x){
	if(ex[x]==0)return add(x);
	ti[v[x]]--;
	if(ti[v[x]]==0)sum--;
	ex[x]=0;
}
void add(int x){
	if(ex[x])return del(x);
	if(ti[v[x]]==0)sum++;
	ti[v[x]]++;
	ex[x]=1;
}
int main(){
	int n,m,i,j,x,y,l,r,sq;
	scanf("%d%d",&n,&m);
	sq=sqrt(n);
	for(i=1;i<=n;i++){
		scanf("%d",v+i);
		mp[v[i]]=1;
	}
	for(i=1,it=mp.begin();it!=mp.end();it++,i++)it->second=i;
	for(i=1;i<=n;i++)v[i]=mp[v[i]];
	for(i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	M=0;
	dep[1]=1;
	dfs(1);
	for(j=1;j<16;j++){
		for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
	}
	for(i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		if(st[x]>st[y])swap(x,y);
		j=lca(x,y);
		q[i].r=st[y];
		if(x==j)
			q[i].l=st[x];
		else{
			q[i].l=ed[x];
			q[i].lca=j;
		}
		q[i].sid=q[i].l/sq;
		q[i].qid=i;
	}
	sort(q+1,q+m+1,cmp);
	l=r=1;
	add(1);
	for(i=1;i<=m;i++){
		while(l>q[i].l){
			l--;
			add(p[l]);
		}
		while(r<q[i].r){
			r++;
			add(p[r]);
		}
		while(l<q[i].l){
			del(p[l]);
			l++;
		}
		while(r>q[i].r){
			del(p[r]);
			r--;
		}
		if(q[i].lca)add(q[i].lca);
		ans[q[i].qid]=sum;
		if(q[i].lca)del(q[i].lca);
	}
	for(i=1;i<=m;i++)printf("%d\n",ans[i]);
}

[SPOJ]COT2的更多相关文章

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

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

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

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

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

  5. SPOJ COT2 树上找路径上不同值的个数

    题目大意 给出多个询问u , v , 求出u-v路径上点权值不同的个数 开始做的是COT1,用主席树写过了,理解起来不难 很高兴的跑去做第二道,完全跟普通数组区间求k个不同有很大区别,完全没思路 膜拜 ...

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

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

  7. spoj COT2(树上莫队)

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

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

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

  9. SPOJ - COT2 离线路径统计

    题意:求\(u\)到\(v\)的最短路径的不同权值种类个数 树上莫队试水题,这一篇是上篇的弱化部分,但可测试以下结论的正确性 设\(S(u,v)\):\(u-v\)最短路径所覆盖的点集 \(S(u,v ...

随机推荐

  1. boost 文件操作

    void testFileSystem() { boost::filesystem::path path("/test/test1"); //初始化 boost::filesyst ...

  2. 解决“并非来自 Chrome 网上应用店。”

    Chrome谷歌浏览器已停用不支持的扩展程序解决方法 第一种方法:(亲测有效) 1.首先把需要安装的第三方插件,后缀.crx 改成 .rar,然后解压,得到一个文件夹 2.再打开chrome://ex ...

  3. Qt 设置应用程序图标(windows)

    Step 1: 创建  xxx.rc 文件. 将ico图标文件复制到项目根目录下.然后在该目录中新建xxx.rc文件,并输入一行代码: IDI_ICON1 ICON DISCARDABLE " ...

  4. oracle导入和导出和授权

    导入数据库: imp demo@orcl file=d:/bak_1023.dmp full=y ignore=y 导出数据库: @orcl file=d:/bak_1023.dmpexp yhtj/ ...

  5. 转:通过Spring Session实现新一代的Session管理

    长期以来,session管理就是企业级Java中的一部分,以致于我们潜意识就认为它是已经解决的问题,在最近的记忆中,我们没有看到这个领域有很大的革新. 但是,现代的趋势是微服务以及可水平扩展的原生云应 ...

  6. 金山中学 rugular SRM 04 ——纪念我的第一次Ak

    虽然只是一场比较简单的比赛 但奈何我也比较弱啊.... T1 一道计算概率的题目 T SRM 04 描述 给个长度为 n 的数列,每次操作能将数列打乱(RandomShuffle),问在期望下需要多少 ...

  7. jquery——通过name属性查找元素

      Js代码 : $("div[id]") 选择所有含有id属性的div元素 $("input[name='newsletter']") 选择所有的name属性 ...

  8. wx.ScrolledWindow wx.PseudoDC

    # encoding: utf-8 import logging import random import wx import wx.lib.inspection def GetMyBitmap(): ...

  9. 【Shell 编程基础第二部分】Shell里的流程控制、Shell里的函数及脚本调试方法!

    http://blog.csdn.net/xiaominghimi/article/details/7603003 本站文章均为李华明Himi原创,转载务必在明显处注明:转载自[黑米GameDev街区 ...

  10. POJ2255(二叉树遍历)

    Tree Recovery Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13000   Accepted: 8112 De ...