Spoj 10628. Count on a tree

Time Limit: 12 Sec  Memory Limit: 128 MB
Submit: 7669  Solved: 1894
[Submit][Status][Discuss]

Description

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

Input

第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
 

Output

M行,表示每个询问的答案。最后一个询问不输出换行符

Sample Input

8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2

Sample Output

2
8
9
105
7

HINT

HINT:
N,M<=100000
暴力自重。。。

Source

 
题解,可持久化权值线段树上二分即可,
很好理解的,我自己写的runtime了好久,不知道为什么。
改成hzwer的就过了,GG。
 
AC代码
 
 #include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstdio> #define N 100007
#define M 2000007
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch>''||ch<''){if (ch=='-') f=-;ch=getchar();}
while(ch<=''&&ch>=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n,m,top,sz,ind;
int a[N],zhi[N];
int num[N],fx[N];
int cnt,head[N],next[*N],rea[*N];
int ls[M],rs[M],sum[M],root[N];
int deep[N],fa[N][]; int find(int x)
{
int l=,r=top;
while(l<=r)
{
int mid=(l+r)>>;
if (zhi[mid]==x) return mid;
if (zhi[mid]<x) l=mid+;
else r=mid-;
}
}
void add(int u,int v)
{
next[++cnt]=head[u];
head[u]=cnt;
rea[cnt]=v;
}
void dfs(int u)
{
ind++,num[ind]=u,fx[u]=ind;
for (int i=;i<=;i++)
fa[u][i]=fa[fa[u][i-]][i-];
for (int i=head[u];i!=-;i=next[i])
{
int v=rea[i];
if (fa[u][]!=v)
{
deep[v]=deep[u]+;
fa[v][]=u;
dfs(v);
}
}
}
int lca(int a,int b)
{
if (deep[a]<deep[b]) swap(a,b);
int i;
for (i=;(<<i)<=deep[a];i++);
i--;
for (int j=i;j>=;j--)
if (deep[a]-(<<j)>=deep[b]) a=fa[a][j];
if (a==b) return a;
for (int j=i;j>=;j--)
if (fa[a][j]!=fa[b][j]) a=fa[a][j],b=fa[b][j];
return fa[a][];
}
void change(int l,int r,int x,int &y,int z)
{
y=++sz;
sum[y]=sum[x]+;
if (l==r) return;
ls[y]=ls[x],rs[y]=rs[x];
int mid=(l+r)>>;
if (z<=mid) change(l,mid,ls[x],ls[y],z);
else change(mid+,r,rs[x],rs[y],z);
}
int query(int l,int r,int a,int b,int c,int d,int rank)
{
if (l==r) return zhi[l];
int mid=(l+r)>>,tmp=sum[ls[a]]+sum[ls[b]]-sum[ls[c]]-sum[ls[d]];
if (tmp>=rank) return query(l,mid,ls[a],ls[b],ls[c],ls[d],rank);
else return query(mid+,r,rs[a],rs[b],rs[c],rs[d],rank-tmp); }
int que(int x,int y,int rk)
{
int a=x,b=y,c=lca(x,y),d=fa[c][];
a=root[fx[a]],b=root[fx[b]],c=root[fx[c]],d=root[fx[d]];
int l=,r=top;
while(l<r)
{
int mid=(l+r)>>;
int tmp=sum[ls[a]]+sum[ls[b]]-sum[ls[c]]-sum[ls[d]];
if(tmp>=rk)r=mid,a=ls[a],b=ls[b],c=ls[c],d=ls[d];
else rk-=tmp,l=mid+,a=rs[a],b=rs[b],c=rs[c],d=rs[d];
}
return zhi[l];
}
int main()
{
memset(head,-,sizeof(head));
n=read(),m=read();
for (int i=;i<=n;i++)
a[i]=read(),zhi[i]=a[i];
sort(zhi+,zhi+n+);
top=;
for (int i=;i<=n;i++)
if (zhi[i]!=zhi[i-]) zhi[++top]=zhi[i];
for (int i=;i<=n;i++)
a[i]=find(a[i]);
for (int i=;i<n;i++)
{
int x=read(),y=read();
add(x,y),add(y,x);
}
dfs();
for (int i=;i<=n;i++)
{
int t=num[i];//从标号的1开始。
change(,top,root[fx[fa[t][]]],root[i],a[t]);
}
int last=;
for(int i=;i<=m;i++)
{
int x=read(),y=read(),rk=read();
x^=last;
last=que(x,y,rk);
printf("%d",last);
if(i!=m)printf("\n");
}
/*for (int i=1;i<=m;i++)
{
int x=read(),y=read(),rank=read();
x^=last;
int a=root[fx[x]],b=root[fx[y]],c=root[fx[lca(x,y)]],d=root[fx[fa[lca(x,y)][0]]];
last=query(1,top,a,b,c,d,rank);
printf("%d",last);
if (i!=m) cout<<endl;
}*/
}

Wrong代码

 #include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstdio> #define N 100007
#define M 3000007
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch>''||ch<''){if (ch=='-') f=-;ch=getchar();}
while(ch<=''&&ch>=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n,m,top,sz,ind;
int a[N],zhi[N];
int num[N],fx[N];
int cnt,head[N],next[*N],rea[*N];
int ls[M],rs[M],sum[M],root[N];
int deep[N],fa[N][]; int find(int x)
{
int l=,r=top;
while(l<=r)
{
int mid=(l+r)>>;
if (zhi[mid]==x) return mid;
if (zhi[mid]<x) l=mid+;
else r=mid-;
}
}
void add(int u,int v)
{
next[++cnt]=head[u];
head[u]=cnt;
rea[cnt]=v;
}
void dfs(int u)
{
ind++,num[ind]=u,fx[u]=ind;
for (int i=;i<=;i++)
fa[u][i]=fa[fa[u][i-]][i-];
for (int i=head[u];i!=-;i=next[i])
{
int v=rea[i];
if (fa[u][]!=v)
{
deep[v]=deep[u]+;
fa[v][]=u;
dfs(v);
}
}
}
int lca(int a,int b)
{
if (deep[a]<deep[b]) swap(a,b);
int i;
for (i=;(<<i)<=deep[a];i++);
i--;
for (int j=i;j>=;j--)
if (deep[a]-(<<j)>=deep[b]) a=fa[a][j];
if (a==b) return a;
for (int j=i;j>=;j--)
if (fa[a][j]!=fa[b][j]) a=fa[a][j],b=fa[b][j];
return fa[a][];
}
void change(int l,int r,int x,int &y,int z)
{
y=++sz;
sum[y]=sum[x]+;
if (l==r) return;
ls[y]=ls[x],rs[y]=rs[x];
int mid=(l+r)>>;
if (z<=mid) change(l,mid,ls[x],ls[y],z);
else change(mid+,r,rs[x],rs[y],z);
}
int query(int l,int r,int a,int b,int c,int d,int rank)
{
if (l==r) return zhi[l];
int mid=(l+r)>>,tmp=sum[ls[a]]+sum[ls[b]]-sum[ls[c]]-sum[ls[d]];
if (tmp>=rank) return query(l,mid,ls[a],ls[b],ls[c],ls[d],rank);
else return query(mid+,r,rs[a],rs[b],rs[c],rs[d],rank-tmp);
}
int main()
{
memset(head,-,sizeof(head));
n=read(),m=read();
for (int i=;i<=n;i++)
a[i]=read(),zhi[i]=a[i];
sort(zhi+,zhi+n+);
top=;
for (int i=;i<=n;i++)
if (zhi[i]!=zhi[i-]) zhi[++top]=zhi[i];
for (int i=;i<=n;i++)
a[i]=find(a[i]);
for (int i=;i<n;i++)
{
int x=read(),y=read();
add(x,y),add(y,x);
}
dfs();
for (int i=;i<=n;i++)
{
int t=num[i];//从标号的1开始。
change(,top,root[fx[fa[t][]]],root[i],a[t]);
}
int last=;
for (int i=;i<=m;i++)
{
int x=read(),y=read(),rank=read();
x^=last;
int a=root[fx[x]],b=root[fx[y]],c=root[fx[lca(x,y)]],d=root[fx[fa[lca(x,y)][]]];
last=query(,top,a,b,c,d,rank);
printf("%d",last);
if (i!=m) cout<<endl;
}
}

bzoj 2588 Spoj 10628. Count on a tree (可持久化线段树)的更多相关文章

  1. BZOJ - 2588 Spoj 10628. Count on a tree (可持久化线段树+LCA/树链剖分)

    题目链接 第一种方法,dfs序上建可持久化线段树,然后询问的时候把两点之间的所有树链扒出来做差. #include<bits/stdc++.h> using namespace std; ...

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

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

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

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

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

  6. Bzoj 2588 Spoj 10628. Count on a tree(树链剖分LCA+主席树)

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MB Description 给定一棵N个节点的树,每个点 ...

  7. 主席树 || 可持久化线段树 || LCA || BZOJ 2588: Spoj 10628. Count on a tree || Luogu P2633 Count on a tree

    题面: Count on a tree 题解: 主席树维护每个节点到根节点的权值出现次数,大体和主席树典型做法差不多,对于询问(X,Y),答案要计算ans(X)+ans(Y)-ans(LCA(X,Y) ...

  8. ●BZOJ 2588 Spoj 10628. Count on a tree

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2588 题解: 主席树,在线,(求LCA)感觉主席树真的好厉害...在原树上建主席树.即对于原 ...

  9. 洛谷 2633 BZOJ 2588 Spoj 10628. Count on a tree

    [题解] 蜜汁强制在线... 每个点开一个从它到根的可持久化权值线段树.查询的时候利用差分的思想在树上左右横跳就好了. #include<cstdio> #include<algor ...

随机推荐

  1. Matlab实现Hough变换检测图像中的直线 分类: 图像处理 2014-06-14 22:07 641人阅读 评论(0) 收藏

    Hough变换的原理: 将图像从图像空间变换至参数空间,变换公式如下: 变换以后,图像空间与参数空间存在以下关系: 图像空间中的一点在参数空间是一条曲线,而图像空间共线的各点对应于参数空间交于一点的各 ...

  2. 最简单的struts实例介绍

    struts2环境配置   struts2框架,大多数框架都在使用.由于工作需要,开始做Java项目.先学个struts2. 一.下载struts2 有好多版本,我下载的是struts-2.2.1.1 ...

  3. 转 ORA-00054 的解决方法

    统有一个不用的索引,想删除这个索引, SQL> drop index GPSTIME_GLOBAL_INDEX  2  /drop index GPSTIME_GLOBAL_INDEX      ...

  4. oracle 安装,启动 ,plsql 连接

    1.下载oracle 服务器端,正常安装,在选择桌面类或者是服务器类的时候选择服务器类. 2.下载oracle 客户端解压版 下载地址   链接:https://pan.baidu.com/s/1mi ...

  5. 【C++】模板简述(四):模板为什么不支持分离编译?

    上文简述了类模板相关功能,本文主要简述为什么模板不支持分离编译? 在C++中,为了一个项目的规范,我们通常把代码归为三类:声明文件.实现文件.测试文件. 比如,我要用C++实现一个链表,那么就会创建这 ...

  6. Vue 拦截器的使用

    拦截器 可以全局进行拦截器设置.拦截器在发送请求前或响应返回时做一些特殊的处理. 拦截器的注册 Vue.http.interceptors.push({ request: function ( req ...

  7. Vue.js语法糖整理

    el:element 需要获取的元素,一定是HTML中的根容器元素 data:用于数据的存储 methods:用于存储各种方法 数据绑定字面量只加载一次{{* msg}} data里面可以进行简单的运 ...

  8. jQuery addClass removeClass toggleClass方法概述

    通过动态改变类名(class),可以让其修改元素呈现出不同的效果.在HTML结构中里,多个class以空格分隔,当一个节点(或称为一个标签)含有多个class时,DOM元素响应的className属性 ...

  9. xamarin 学习笔记02- IOS Simulator for windows 安装

    微软发布了在window下的ios模拟器 下载 ios模拟器 并安装在windows系统上. Xamarin for Visual Studio 和 网络上的 Mac 中的 Xamarin.iOS 开 ...

  10. python学习日记-01

    一. 熟悉 在正式介绍python之前,了解下面两个基本操作对后面的学习是有好处的: (1)基本的输入输出 可以在Python中使用+.-.*./直接进行四则运算. >>> 1+3* ...