[luogu P2633] Count on a tree

[luogu P2633] Count on a tree

题目描述

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

输入输出格式

输入格式:

 

第一行两个整数N,M。

第二行有N个整数,其中第i个整数表示点i的权值。

后面N-1行每行两个整数(x,y),表示点x到点y有一条边。

最后M行每行两个整数(u,v,k),表示一组询问。

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 复制
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
输出样例#1: 复制
2
8
9
105
7

说明

HINT:

N,M<=100000

暴力自重。。。

来源:bzoj2588 Spoj10628.

本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。

主席树的变形,离散后,对于每个点u构造一棵新的主席树都建立在以fa[u][0]构造的主席树的基础之上。

其中,要按照dfs序来造,才能保证正确性。(用bfs序当然也可以咯)

然后询问两个点(x,y)时,根据主席树可加减的性质,只要在tree[x]+tree[y]-tree[lca(x,y)]-tree[fa[lca(x,y)]]这棵树上查询就可以了。

注意强制在线。

code:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <tr1/unordered_map>
  5 #define ms(a,x) memset(a,x,sizeof a)
  6 using namespace std;
  7 void OJ() {
  8     #ifndef ONLINE_JUDGE
  9         freopen("in.txt","r",stdin);
 10         freopen("out.txt","w",stdout);
 11     #endif
 12 }
 13 
 14 namespace fastIO {
 15     #define gec(c) getchar(c)
 16     #define puc(c) putchar(c)
 17     char ch;
 18     inline int read() {
 19         int x=0,f=1; ch=getchar();
 20         while (ch<'0'||ch>'9') {
 21             if (ch=='-') f=-f;
 22             ch=gec();
 23         }
 24         while (ch>='0'&&ch<='9') {
 25             x=(x<<3)+(x<<1)+ch-'0';
 26             ch=getchar();
 27         }
 28         return x*f;
 29     }
 30     int ttt,nnn[20];
 31     template <class T> inline void write(T x) {
 32         if (x==0) {
 33             puc('0'); return;
 34         }
 35         if (x<0) x=-x,puc('-');
 36         for (ttt=0; x; x/=10) nnn[++ttt]=x%10;
 37         for (; ttt; --ttt) puc(nnn[ttt]+48);
 38     }
 39     inline void newline() {
 40         puc('\n');
 41     }
 42 } using namespace fastIO;
 43 
 44 const int N=100005;
 45 int n,m,cnt,b[N];
 46 int tot,lnk[N],nxt[N<<1],son[N<<1];
 47 int dep[N],fa[N][20],dfn[N],rel[N],clo;
 48 tr1::unordered_map <int,int> ref;
 49 struct data {
 50     int x,i;
 51 } a[N];
 52 inline bool cmp_x (const data &u,const data &v) {
 53     return u.x<v.x;
 54 }
 55 inline bool cmp_i (const data &u,const data &v) {
 56     return u.i<v.i;
 57 }
 58 struct node {
 59     node* l,* r; int v;
 60     node () {
 61         l=r=0,v=0;
 62     }
 63 } *r[N];
 64 #define M ((l)+(r)>>1)
 65 inline void setup (node* &c,int l,int r) {
 66     c=new node();
 67     if (l==r) return;
 68     setup(c->l,l,M),setup(c->r,M+1,r);
 69 }
 70 inline void insert (node* &c,int l,int r,int x,node* his) {
 71     c=new node();
 72     c->l=his->l,c->r=his->r,c->v=his->v+1;
 73     if (l==r) return;
 74     if (x<=M) insert(c->l,l,M,x,his->l);
 75     else insert(c->r,M+1,r,x,his->r);
 76 }
 77 inline int reply (node* x,node* y,node* z,node* o,int l,int r,int k,int v=0) {
 78     if (l==r) return b[l];
 79     v+=x->l->v,v+=y->l->v;
 80     v-=z->l->v,v-=o->l->v;
 81     if (k<=v) return reply(x->l,y->l,z->l,o->l,l,M,k);
 82     else return reply(x->r,y->r,z->r,o->r,M+1,r,k-v);
 83 }
 84 void add (int x,int y) {
 85     nxt[++tot]=lnk[x],lnk[x]=tot,son[tot]=y;
 86 }
 87 void dfs (int x,int p) {
 88     dep[x]=dep[p]+1,fa[x][0]=p,rel[dfn[x]=++clo]=x;
 89     for (int j=1; j<=18; ++j) fa[x][j]=fa[fa[x][j-1]][j-1];
 90     for (int j=lnk[x]; j; j=nxt[j]) {
 91         if (son[j]!=p) dfs(son[j],x);
 92     }
 93 }
 94 int lca (int x,int y) {
 95     if (dep[x]<dep[y]) swap(x,y);
 96     if (y==1) return 1;
 97     int dif=dep[x]-dep[y];
 98     for (int j=18; ~j; --j)
 99         if (dif&(1<<j)) x=fa[x][j];
100     if (x==y) return x;
101     for (int j=18; ~j; --j)
102         if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
103     return fa[x][0];
104 }
105 int main() {
106     OJ(); int x,y,z,o,k,lastans=0;
107     n=read(),m=read();
108     for (int i=1; i<=n; ++i) a[i].x=read();
109     for (int i=1; i<n; ++i) {
110         x=read(),y=read();
111         add(x,y),add(y,x);
112     }
113     dep[0]=0,dfn[0]=0,dfs(1,0);
114     for (int i=1; i<=n; ++i) a[i].i=dfn[i];
115     sort(a+1,a+1+n,cmp_x);
116     b[cnt=ref[a[1].x]=1]=a[1].x;
117     for (int i=2; i<=n; i++)
118         if (a[i].x!=a[i-1].x) b[ref[a[i].x]=++cnt]=a[i].x;
119     sort(a+1,a+1+n,cmp_i);
120     setup(r[0],1,cnt);
121     for (int i=1; i<=n; ++i) insert(r[i],1,cnt,ref[a[i].x],r[dfn[fa[rel[i]][0]]]);
122     for (int i=1; i<=m; ++i) {
123         x=read(),x^=lastans,y=read(),z=lca(x,y),o=fa[z][0],k=read();
124         x=dfn[x],y=dfn[y],z=dfn[z],o=dfn[o];
125         write(lastans=reply(r[x],r[y],r[z],r[o],1,cnt,k));
126         if (i^m) newline();
127     }
128     return 0;
129 }
View Code

转载于:https://www.cnblogs.com/whc200305/p/7953283.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值