Count on a Tree

传送门

这次主席树要维护的是树上信息啦。

其实主席树基本的思想还是用前缀和,那么我们就仿照一下,在树上做前缀和就好啦。我们令第\(i\)个节点所在的主席树维护该点到根节点路径上的所有数(值域是数的值),之后在计算的时候,以\(v[p] + v[q] - v[lca(p,q)] - v[fa[lca(p,q)]]\)为标准来判定往哪边二分就可以了。

直接在\(dfs\)的时候建树即可,我使用\(ST\)表求\(lca\),其他的也无所谓。这题还是很好写的。

看一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<vector>
#include<map>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define fr friend inline
#define y1 poj
#define mp make_pair
#define pr pair<int,int>
#define fi first
#define sc second
#define pb push_back

using namespace std;
typedef long long ll;
const int M = 200005;
const int N = 1000005;

const int INF = 1000000009;
const double eps = 1e-7;

int read()
{
    int ans = 0,op = 1;char ch = getchar();
    while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
    return ans * op;
}

struct node
{
   int ls,rs,v;
}t[N<<3];

struct edge
{
   int next,to;
}e[M<<1];

int a[M],b[M],n,m,root[M<<1],la,x,y,z,head[M],ecnt,dep[M],dfn[M<<1],pos[M],idx,lg[M<<1];
int st[22][M<<1],cnt,fat[M<<1],tot;

void add(int x,int y)
{
   e[++ecnt].to = y;
   e[ecnt].next = head[x];
   head[x] = ecnt;
}

void modify(int old,int &p,int l,int r,int pos)
{
   p = ++cnt;
   t[p].ls = t[old].ls,t[p].rs = t[old].rs,t[p].v = t[old].v + 1;
   if(l == r) return;
   int mid = (l+r) >> 1;
   if(pos <= mid) modify(t[old].ls,t[p].ls,l,mid,pos);
   else modify(t[old].rs,t[p].rs,mid+1,r,pos);
}

int query(int p,int q,int f,int g,int l,int r,int k)
{
   if(l == r) return l;
   int mid = (l+r) >> 1;
   int sum = t[t[p].ls].v + t[t[q].ls].v - t[t[f].ls].v - t[t[g].ls].v;
   if(k <= sum) return query(t[p].ls,t[q].ls,t[f].ls,t[g].ls,l,mid,k);
   else return query(t[p].rs,t[q].rs,t[f].rs,t[g].rs,mid+1,r,k - sum);
}

int Min(int p,int q)
{
   return (dep[p] < dep[q]) ? p : q;
}

void dfs(int x,int fa)
{
   dep[x] = dep[fa] + 1,dfn[++idx] = x,pos[x] = idx,fat[x] = fa;
   modify(root[fa],root[x],1,tot,a[x]);
   for(int i = head[x];i;i = e[i].next)
   {
      if(e[i].to != fa) dfs(e[i].to,x);
      dfn[++idx] = x;
   }
}

void build()
{
   lg[0] = -1;
   rep(i,1,idx) st[0][i] = dfn[i];
   rep(i,1,idx) lg[i] = lg[i>>1] + 1;
   rep(j,1,lg[idx])
   rep(i,1,idx)
   {
      if(i + (1 << j) - 1 > idx) break;
      st[j][i] = Min(st[j-1][i],st[j-1][i + (1 << (j-1))]);
   }
}

int lca(int x,int y)
{
   int kl = pos[x],kr = pos[y];
   if(kl > kr) swap(kl,kr);
   int k = lg[kr - kl + 1];
   return Min(st[k][kl],st[k][kr - (1 << k) + 1]);
}

int main()
{
   n = read(),m = read();
   rep(i,1,n) a[i] = b[i] = read();
   sort(b+1,b+1+n);
   tot = unique(b+1,b+1+n) - b - 1;
   rep(i,1,n) a[i] = lower_bound(b+1,b+1+tot,a[i]) - b;
   rep(i,1,n-1) x = read(),y = read(),add(x,y),add(y,x);
   dfs(1,0),build();
   rep(i,1,m)
   {
      x = read(),y = read(),z = read();
      x ^= la;
      int g = lca(x,y),f = fat[g];
      //printf("#%d %d %d %d\n",x,y,g,f);
      int now = query(root[x],root[y],root[f],root[g],1,tot,z);
      //printf("$%d\n",now);
      la = b[now];
      printf("%d\n",la);
   }
   return 0;
}

posted @ 2018-12-11 15:54  CaptainLi  阅读(256)  评论(0编辑  收藏  举报