bzoj 2588

树上用主席树的话,对每个点到根的区间开个线段树

然后每次询问求出lca后就能用区间减法了(链剖的代码还是挺好看的)

弄了好久只是空间的问题,开空间也不能太随意。。

 1 #include<bits/stdc++.h>
 2 #define inc(i,l,r) for(int i=l;i<=r;i++)
 3 #define dec(i,l,r) for(int i=l;i>=r;i--)
 4 #define link(x) for(edge *j=h[x];j;j=j->next)
 5 #define mem(a) memset(a,0,sizeof(a))
 6 #define inf 1e9
 7 #define ll long long
 8 #define succ(x) (1<<x)
 9 #define NM 200000+5
10 using namespace std;
11 int read(){
12     int x=0,f=1;char ch=getchar();
13     while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
14     while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar();
15     return x*f;
16 }
17 struct edge{
18     int t,v;
19     edge *next;
20 }e[2*NM],*h[NM],*_o=e,*null;
21 void add(int x,int y){
22     _o++;_o->t=y;_o->next=h[x];h[x]=_o;
23 }
24 struct node{
25     int s;
26     node *l,*r;
27 }T[20*NM],*root[NM],*o=T;
28 int d[NM],f[NM],top[NM],son[NM],size[NM],TOP;
29 int n,m,_t,cnt,a[NM],b[NM],_x,_y,_p;
30 node* mod(node *p,int x,int y){
31     int t=x+y>>1;node *r=++o;
32     *o=*p;r->s++;
33     if(x==y)return r;
34     if(_t<=t)r->l=mod(p->l,x,t);
35     else r->r=mod(p->r,t+1,y);
36     return r;
37 }
38 void dfs1(int x){
39     _t=a[x];root[x]=mod(root[f[x]],1,cnt);
40     link(x)
41     if(!d[j->t]){
42         f[j->t]=x;d[j->t]=d[x]+1;
43         dfs1(j->t);
44         size[x]+=size[j->t];
45         if(size[j->t]>size[son[x]])son[x]=j->t;
46     }
47     size[x]++;
48 }
49 void dfs2(int x){
50     top[x]=TOP;
51     if(son[x])dfs2(son[x]);
52     link(x)if(!top[j->t])dfs2(TOP=j->t);
53 }
54 int lca(int x,int y){
55     if(top[x]==top[y])return d[x]<d[y]?x:y;
56     return d[top[x]]>d[top[y]]?lca(f[top[x]],y):lca(x,f[top[y]]);
57 }
58 int query(node *r1,node *r2,node *r3,node *r4,int x,int y,int k){
59     int t=x+y>>1,v=r1->l->s+r2->l->s-r3->l->s-r4->l->s;
60     if(x==y)return b[x];
61     if(k<=v)return query(r1->l,r2->l,r3->l,r4->l,x,t,k);
62     else return query(r1->r,r2->r,r3->r,r4->r,t+1,y,k-v);
63 }
64 int main(){
65     freopen("data.in","r",stdin);
66     n=read();m=read();
67     inc(i,1,n)b[i]=a[i]=read();
68     sort(b+1,b+n+1);
69     cnt=unique(b+1,b+n+1)-b-1;
70     inc(i,1,n)a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
71     inc(i,1,n-1){
72         _x=read();_y=read();
73         add(_x,_y);add(_y,_x);
74     }
75     d[1]++;root[0]=++o;root[0]->l=o;root[0]->r=o;
76     dfs1(1);
77 //    inc(i,1,n)printf("%d ",son[i]);printf("\n");
78     dfs2(TOP=1);
79 //    inc(i,0,n)printf("%d ",root[i]->s);printf("\n");
80     while(m--){
81         _x=read()^_p;_y=read();_t=read();
82         _p=lca(_x,_y);
83         _p=query(root[_x],root[_y],root[_p],root[f[_p]],1,cnt,_t);
84         printf("%d",_p);if(m)putchar(‘\n‘);
85     }
86     return 0;
87 }

时间: 2024-10-07 04:12:08

bzoj 2588的相关文章

BZOJ 2588: Spoj 10628. Count on a tree 主席树+lca

2588: Spoj 10628. Count on a tree 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),表示一组询问.

bzoj 2588: Spoj 10628. Count on a tree LCA+主席树

2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数

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[Submit][Status][Discuss] Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一

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/JudgeOnline/problem.php?id=2588 Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Inp

bzoj 2588 Count on a tree

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行,表示每个询问的答案.最后一个询问不输出换行符 S

bzoj 2588: Spoj 10628. Count on a tree

DFS序在树上建出主席树,然后..... 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #define ll long long 8 #define M 200009 9 using namespace std; 10 ll read()

AC日记——Count on a tree bzoj 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行,表示每个询问的答案.最后一个询问不输出换行符 S

BZOJ 2588 Count on a tree (COT) 是持久的段树

标题效果:两棵树之间的首次查询k大点的权利. 思维:树木覆盖树,事实上,它是正常的树木覆盖了持久段树. 由于使用权值段树可以寻求区间k大,然后应用到持久段树思想,间隔可以做减法.详见代码. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define NIL (tree[0]) using names

BZOJ 2588 Count on a tree (COT) 可持久化线段树

题目大意:查询树上两点之间的第k大的点权. 思路:树套树,其实是正常的树套一个可持久化线段树.因为利用权值线段树可以求区间第k大,然后再应用可持久化线段树的思想,可以做到区间减法.详见代码. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define NIL (tree[0]) using name