您的位置:首页 > 其它

BZOJ2588 Spoj 10628. Count on a tree

2016-03-02 17:24 369 查看
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2588

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行,表示每个询问的答案。

建立一棵可持久化权值线段树,对于树上的每一个点,以它的父亲节点为上一个版本,根节点的父亲节点是0

询问u与v节点之间第K小的点权,就是询问 (root,u) + (root,v) - (root,lca(u,v)) - (root,fa(lca(u,v))) 第K小的点权,在权值线段树上二分即可。

debug记:建可持久化线段树要从根节点往下建而不是按照点的编号建。不要把建树写残。

Orz教主的指针版主席树,跑得比香港记者还快……

2016.3.2 17:34 update:这份代码在SPOJ上跑了#16……教主的居然WA了?

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define rep(i,l,r) for(int i=l; i<=r; i++)
#define clr(x,y) memset(x,y,sizeof(x))
#define travel(x) for(Edge *p=last[x]; p; p=p->pre)
using namespace std;
const int maxn = 100010;
inline int read(){
int ans = 0, f = 1;
char c = getchar();
for(; !isdigit(c); c = getchar())
if (c == '-') f = -1;
for(; isdigit(c); c = getchar())
ans = ans * 10 + c - '0';
return ans * f;
}
struct Edge{
Edge* pre; int to,cost;
}edge[maxn<<1],*last[maxn],*pt = edge;
int n,m,k,x,y,N,cnt=0,lastans=0,w[maxn],id[maxn],dep[maxn],fa[maxn],size[maxn],top[maxn];
int rt[maxn],ls[maxn*20],rs[maxn*20],sum[maxn*20];
bool vis[maxn];
inline void addedge(int x,int y){
pt->pre = last[x]; pt->to = y; last[x] = pt++;
}
void dfs(int x){
vis[x] = 1; size[x] = 1;
travel(x){
if (vis[p->to]) continue;
dep[p->to] = dep[x] + 1;
fa[p->to] = x;
dfs(p->to); size[x] += size[p->to];
}
}
void dfs(int x,int chain){
int k = 0; top[x] = chain;
travel(x) if (dep[p->to] > dep[x] && size[p->to] > size[k]) k = p->to;
if (!k) return;
dfs(k,chain);
travel(x) if (p->to != k && dep[p->to] > dep[x])
dfs(p->to,p->to);
}
inline int lca(int x,int y){
while (top[x] != top[y]){
if (dep[top[x]] < dep[top[y]]) swap(x,y);
x = fa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
void insert(int l,int r,int x,int &y,int v){
y = ++cnt; sum[y] = sum[x] + 1;
if (l == r) return;
ls[y] = ls[x]; rs[y] = rs[x];
int mid = (l + r) >> 1;
if (v <= mid) insert(l,mid,ls[x],ls[y],v);
else insert(mid+1,r,rs[x],rs[y],v);
}
int query(int x,int y,int k){
int a = x, b = y, c = lca(x,y), d = fa[c];
a = rt[a], b = rt[b], c = rt[c], d = rt[d];
int l = 1, r = N;
while (l < r){
int mid = (l + r) >> 1;
int now = sum[ls[a]] + sum[ls[b]] - sum[ls[c]] - sum[ls[d]];
if (now >= k) r = mid, a = ls[a], b = ls[b], c = ls[c], d = ls[d];
else k -= now, l = mid + 1, a = rs[a], b = rs[b], c = rs[c], d = rs[d];
}
return id[l];
}
void build(int x){
travel(x) if (p->to != fa[x]) insert(1,N,rt[x],rt[p->to],w[p->to]);
travel(x) if (p->to != fa[x]) build(p->to);
}
int main(){
n = read(); m = read(); clr(last,0);
rep(i,1,n) w[i] = id[i] = read();
rep(i,1,n-1){
x = read(); y = read(); addedge(x,y); addedge(y,x);
}
sort(id+1,id+n+1);
N = unique(id+1,id+n+1) - id - 1;
rep(i,1,n) w[i] = lower_bound(id+1,id+N+1,w[i]) - id;
clr(vis,0); dep[1] = 0; fa[1] = 0; dfs(1); dfs(1,1);
insert(1,N,rt[0],rt[1],w[1]);
build(1);
rep(i,1,m){
x = read(); y = read(); k = read();
x ^= lastans;
lastans = query(x,y,k);
printf("%d",lastans);
if (i != m) printf("\n");
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: