Time Limit: 20 Sec  Memory Limit: 400 MB

Description

  给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

Input

  第一行两个整数N,M。
  第二行有N个整数,其中第i个整数表示点i的权值。
  后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
  最后M行每行两个整数(u,v),表示一组询问。
  数据范围是N<=40000 M<=100000 点权在int范围内 

Output

  M行,表示每个询问的答案。

Sample 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
  3 8

Sample Output

  4
  4

Solution

  在线莫队(TLE):把树分成k块,每块选出一个点作为代表点,预处理出所有块的代表点到其他代表点路径上颜色种数和各种颜色的数量,每次询问找到两个询问点所在块,根据预处理出的信息可以在$O(\frac{n}{k})$时间内算出答案,复杂度$O(nk^{2}+\frac{qn}{k})$,适当调整k,总复杂度约为$O(n^{\frac{5}{3}})$,理论上很科学可是这题卡常……
  正解树分块+可持久化块状数组:把树分成k块,每块选出一个点作为代表点,预处理出各块代表点到其他所有点路径上的颜色种数,对于每个询问x,y,我们令所在块的代表点深度较大的为x,代表点为u,则我们利用预处理的信息可以知道u到y的路径上的答案,接下来我们把x到u的路径并入答案中,只要能支持$O(1)$询问一种颜色是否在u到y的路径上出现过即可$O(\frac{n}{k})$完成,我们预处理出每个点到根路径上各种颜色出现的最大深度,那么如果u到根和y到根出现一种颜色的最大深度大等于lca(u,y)的深度,那么这种颜色就在u到y的路径上出现过,暴力计算是$O(n^{2})$的,用可持久化块状数组我们就能实现$O(\sqrt{n})$从一个点的父亲那里复制数组,$O(\sqrt{n})$时间内修改一个元素,$O(1)$查询一个值,总复杂度约为$O(n\sqrt{n})$。

Code

在线莫队(TLE)

#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
inline int read()
{
int x,f=;char c;
while((c=getchar())<''||c>'')if(c=='-')f=;
for(x=c-'';(c=getchar())>=''&&c<='';)x=x*+c-'';
return f?x:-x;
}
#define MN 40000
#define K 713
#define LG 15
#define KS (MN/K)
map<int,int> mp;
struct edge{int nx,t;}e[MN*+];
int h[MN+],en,c[MN+],cnt,fa[LG+][MN+],d[MN+],s[MN+],ht[MN+],q[MN+],qr,b[MN+],p[KS+];
unsigned short ans[KS+][KS+],f[KS+][KS+][MN+];
bool u[KS+][KS+][MN+];
inline void ins(int x,int y)
{
e[++en]=(edge){h[x],y};h[x]=en;
e[++en]=(edge){h[y],x};h[y]=en;
}
void pre(int x)
{
for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa[][x])
{
fa[][e[i].t]=x;d[e[i].t]=d[x]+;
pre(e[i].t);
s[x]+=s[e[i].t];ht[x]=max(ht[x],ht[e[i].t]+);
}
if(++s[q[++qr]=x],(ht[x]=max(ht[x],))==K||x<)
{for(p[++cnt]=x;s[x]--;)b[q[qr--]]=cnt;ht[x]=s[x]=;}
}
inline void cal(int a,int b,int x)
{
(u[a][b][x]^=)?f[a][b][c[x]]++?:++ans[a][b]:
--f[a][b][c[x]]?:--ans[a][b];
}
int lca(int x,int y)
{
int dx=d[x]-d[y],i;
if(dx<)swap(x,y),dx=-dx;
for(i=;dx;++i,dx>>=)if(dx&)x=fa[i][x];
if(x==y)return x;
for(i=LG;i>=;--i)if(fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y];
return fa[][x];
}
int main()
{
int n,m,i,j,x,y,l=,lx=,ly=;
n=read();m=read();
for(i=;i<=n;++i)mp[c[i]=read()]?:mp[c[i]]=++cnt;
for(i=;i<=n;++i)c[i]=mp[c[i]];
for(i=;i<n;++i)ins(read(),read());
cnt=;pre();
for(i=;i<=LG;++i)for(j=;j<=n;++j)fa[i][j]=fa[i-][fa[i-][j]];
for(i=;i<=cnt;++i)for(j=;j<=cnt;++j)
for(x=p[i],y=p[j];x!=y;)
if(d[x]>d[y])cal(i,j,x),x=fa[][x];
else cal(i,j,y),y=fa[][y];
while(m--)
{
i=b[x=read()^l];j=b[y=read()];
if(x==lx&&y==ly){printf("%d\n",l);continue;}
cal(i,j,q[qr=]=lca(lx=x,ly=y));
while(x!=p[i])cal(i,j,q[++qr]=x),x=fa[][x];
while(y!=p[j])cal(i,j,q[++qr]=y),y=fa[][y];
printf("%d\n",l=ans[i][j]);
for(x=;x<=qr;++x)cal(i,j,q[x]);
}
}
正解

#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
inline int read()
{
int x,f=;char c;
while((c=getchar())<''||c>'')if(c=='-')f=;
for(x=c-'';(c=getchar())>=''&&c<='';)x=x*+c-'';
return f?x:-x;
}
#define MN 40000
#define K 200
#define LG 15
map<int,int> mp;
struct edge{int nx,t;}e[MN*+];
int h[MN+],en,c[MN+],cnt,fa[LG+][MN+],d[MN+],s[MN+],ht[MN+],q[MN+],qn;
int b[MN+],p[K+],u[MN+],ans[K+][MN+],a[MN+][K],v[MN+][K],vn;
inline void ins(int x,int y)
{
e[++en]=(edge){h[x],y};h[x]=en;
e[++en]=(edge){h[y],x};h[y]=en;
}
void pre(int x)
{
for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa[][x])
{
fa[][e[i].t]=x;d[e[i].t]=d[x]+;
pre(e[i].t);
s[x]+=s[e[i].t];ht[x]=max(ht[x],ht[e[i].t]+);
}
if(++s[q[++qn]=x],(ht[x]=max(ht[x],))==K||x<)
{for(p[++cnt]=x;s[x]--;)b[q[qn--]]=cnt;ht[x]=s[x]=;}
}
void dfs(int k,int x,int f)
{
if(!u[c[x]]++)++ans[k][x];
if(!f)ans[k][fa[][x]]=ans[k][x],dfs(k,fa[][x],x);
else for(int i=h[x];i;i=e[i].nx)if(e[i].t!=f)
ans[k][e[i].t]=ans[k][x],dfs(k,e[i].t,x);
--u[c[x]];
}
void build(int x)
{
int i,j=c[x]/K,k=c[x]%K;
for(i=;i<K;++i)a[x][i]=a[fa[][x]][i];
for(++vn,i=;i<K;++i)v[vn][i]=v[a[x][j]][i];
v[a[x][j]=vn][k]=d[x];
for(i=h[x];i;i=e[i].nx)if(e[i].t!=fa[][x])build(e[i].t);
}
int lca(int x,int y)
{
int dx=d[x]-d[y],i;
if(dx<)swap(x,y),dx=-dx;
for(i=;dx;++i,dx>>=)if(dx&)x=fa[i][x];
if(x==y)return x;
for(i=LG;i>=;--i)if(fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y];
return fa[][x];
}
int vio(int x,int y)
{
int res=;
for(qn=;x!=y;)
d[x]>d[y]?(u[q[++qn]=c[x]]++?:++res,x=fa[][x]):
(u[q[++qn]=c[y]]++?:++res,y=fa[][y]);
u[q[++qn]=c[x]]++?:++res;
while(qn)u[q[qn--]]=;
return res;
}
int main()
{
int n,m,i,j,x,y,l=;
n=read();m=read();
for(i=;i<=n;++i)mp[c[i]=read()]?:mp[c[i]]=++cnt;
for(i=;i<=n;++i)c[i]=mp[c[i]]-;
for(i=;i<n;++i)ins(read(),read());
cnt=;pre(d[]=);
for(i=;i<=LG;++i)for(j=;j<=n;++j)fa[i][j]=fa[i-][fa[i-][j]];
for(i=;i<=cnt;++i)dfs(i,p[i],);
build();
while(m--)
{
x=read()^l;y=read();
if(b[x]==b[y])l=vio(x,y);
else
{
if(d[p[b[x]]]<d[p[b[y]]])swap(x,y);
l=ans[b[x]][y];j=d[lca(x,y)];
for(i=x;i!=p[b[x]];i=fa[][i])if(!u[c[i]]++)
if(max(v[a[p[b[x]]][c[i]/K]][c[i]%K],v[a[y][c[i]/K]][c[i]%K])<j)++l;
for(i=x;i!=p[b[x]];i=fa[][i])u[c[i]]=;
}
printf("%d\n",l);
}
}

[BZOJ]2589: Spoj 10707 Count on a tree II的更多相关文章

  1. 【BZOJ2589】 Spoj 10707 Count on a tree II

    BZOJ2589 Spoj 10707 Count on a tree II Solution 吐槽:这道题目简直...丧心病狂 如果没有强制在线不就是树上莫队入门题? 如果加了强制在线怎么做? 考虑 ...

  2. BZOJ2539 Spoj 10707 Count on a tree II

    题面 题解 因为这道题目我也不太会做,所以借鉴了一下大佬heyujun的博客 如果不强制在线,这道题目是树上莫队练手题 我们知道莫队是离线的,但是万一强制在线就凉凉了 于是我们就需要一些操作:树分块 ...

  3. bzoj2589: Spoj 10707 Count on a tree II

    Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权.其中lastans是上一个询问的答案,初 ...

  4. 【SPOJ】Count On A Tree II(树上莫队)

    [SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...

  5. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

  6. BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

    2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/J ...

  7. Bzoj 2588: Spoj 10628. Count on a tree 主席树,离散化,可持久,倍增LCA

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2588 2588: Spoj 10628. Count on a tree Time Limit ...

  8. BZOJ 2588: Spoj 10628. Count on a tree( LCA + 主席树 )

    Orz..跑得还挺快的#10 自从会树链剖分后LCA就没写过倍增了... 这道题用可持久化线段树..点x的线段树表示ROOT到x的这条路径上的权值线段树 ----------------------- ...

  9. bzoj 2588 Spoj 10628. Count on a tree (可持久化线段树)

    Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 7669  Solved: 1894[Submi ...

随机推荐

  1. 实验四Java Android简易开发

    实验准备 Android Studio下载 Android Studio安装 实验内容 Android Stuidio的安装测试 Android Stuidio的安装测试: 参考<Java和An ...

  2. 201621123057 《Java程序设计》第13周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 为你的系统增加网络功能(购物车.图书馆管理.斗地主等)-分组完成 为了让你的系统可以被多个用户通过网 ...

  3. 201621123057 《Java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 在上一周的总结上做了一点补充 1.2 选做:收集你认为有用的代码片段 2. 书面作业 本次作业题集集合 1. ...

  4. python的dir、help、str用法

    当你给dir()提供一个模块名字时,它返回在那个模块中定义的名字的列表.当没有为其提供参数时, 它返回当前模块中定义的名字的列表.dir() 函数使用举例: 1 2 3 4 5 6 >>& ...

  5. 关于安装win7系统时出现0x0000007b电脑蓝屏代码的问题

    问题解析: 0X0000007B 这个错误网上都说是sata硬盘的什么引导模式的原因引起. 在网上查找了很久,大概引起错误的原因就是:sata和ide两种模式不同,前者可以装win7系统,后者是xp系 ...

  6. linux下面的智能解压脚本smart解压

    file命令可以辨别出一个给定文件的文件类型,如:file lf.gz,其输出结果为: lf.gz: gzip compressed data, deflated, original filename ...

  7. spring6——AOP的编程术语

    面向切面编程作为一种编程思想,允许我们对程序的执行流程及执行结果动态的做出改变,以达到业务逻辑之间的分层管理或者是目标对象方法的增强,spring框架很好的实现了这种编程思想,让我们可以对主业务逻辑和 ...

  8. Python之线程

    操作系统线程理论 线程概念的引入背景 进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别 ...

  9. ST-LINK V2 DIY笔记(一)

    最近一段时间调试STM32板子的时候,都是用JLINK+杜邦线,或者拿官方板子当STLINK用,可以用,但是体积比较大,有时候觉得比较麻烦.正好前一阵手头项目少,就想DIY一个STLINK. 图是网上 ...

  10. window10下安装linux虚拟机

    一.准备工具 虚拟机.镜像.putty 1.安装虚拟机 VMware Workstation Pro 安装成功之后需要输入密钥,请点击以下链接 http://www.360doc.com/conten ...