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. 工作记录 SQL prompt .net平台版本安装

    昨天泡脚了,虽然依然睡的很晚,但是身体很舒服,尽量坚持把 上午尝试用一根网线,链接服务器和笔记本,但是设置好了,Ping不通. 下午安装SQL插件SQL prompt https://www.cnbl ...

  2. WPF学习10:基于MVVM Light 制作图形编辑工具(1)

    图形编辑器的功能如下图所示: 除了MVVM Light 框架是一个新东西之外,本文所涉及内容之前的WPF学习0-9基本都有相关介绍. 本节中,将搭建编辑器的界面,搭建MVVM Light 框架的使用环 ...

  3. Windows10系统切换JDK版本(前提是装了多个版本的JDK)

    由于是直接截屏,等我回过头来整理的时候忘记了文章原来的出处, 如作者本人看到,如有侵权,请联系删除!

  4. java JDK在windows及mac下安装配置

    windows下安装: JDK下载 地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151. ...

  5. 【PostgreSQL-9.6.3】一般视图

    PG视图分为两种,一种是物化视图,一种是一般视图.本篇文章主要写一般视图哪些事儿.所谓一般视图,通俗点说,就是由查询语句定义的虚拟表.视图中的数据可能来自一张或多张表. 1. 视图创建语句 CREAT ...

  6. pythno学习小结-替换python字典中的key值

    源: d={'a':1,'b':2,'c':3} 目标:key:'b'替换为'e' d={'a':1,'e':2,'c':3} 方法: d['e']=d.pop('b')

  7. c语言 c++ 实现查看本地ip,外网ip, 本地主机名,查看http网址对应的ip

    /******************************************************************************* 作者 :邓中强 Email :1246 ...

  8. webstorm下开发微信小程序

  9. JavaSE-21 字符编码简介

    ASCII ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英 ...

  10. DataRow复制一行到另一个DataTable

    DataRow复制一行到另一个DataTable   下面两个方法是DataRow复制一行到另一个DataTable的,直接Add会出错“此行已属于另一个表”,其实以前就知道怎么做的,可每次要用到的时 ...