洛谷 P2633 Count on a tree 主席树、lca、前缀

P2633 Count on a tree

题目链接

题目大意

给一棵树,有点权,每次询问,x到y路径上点点权的第k小是多少?
强制在线,

题解

第k小,肯定会想到主席树。
但是怎么处理呢?
数组中求区间第k小的方法是 把数组的每个前缀建个权值线段树,然后要查询 l~r 区间的值,就用r的权值线段树中的数量减去l - 1中的就好了。也就是T® - T(l - 1)

现在是在树里面。
方法是:根节点到每个点都建个权值线段树。(当然是主席树那样的,)
然后现在知道了根到每个点,怎么求一个路径上的?
当然是 T(x) + T(y) - T(lca(x,y)) - T(fa(lca(x,y)));
这样求个第k大就好了。
然后就是板子题了。。
记得离散化!
lca板子+主席树板子
就完了。。
一定要有前缀的思想!!!
懂得自闭一晚上找不到bug的感觉吗。。。
洛谷 P2633 Count on a tree 主席树、lca、前缀_第1张图片
建树的时候一定不要手贱写个x != 0 才新建点!!! 这错误都能犯我也是很shabi了
代码:

#include
#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef unsigned long long ull;
typedef unordered_set<int>::iterator sit;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void tempwj(){freopen("P2633_1.in","r",stdin);freopen("P2633_1.out","w",stdout);}
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){a %= mod;ll ans = 1;while(b > 0){if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp{bool operator()(const pii & a, const pii & b){return a.second > b.second;}};
int lb(int x){return  x & -x;}
//friend bool operator < (Node a,Node b)   重载
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
const int maxn = 1e6+10;
const int M = 1e6 + 2;

struct Node
{
	int l,r,num;
}node[maxn * 40];
int cnt = 0;
int root[maxn];
void build(int l,int r,int& x,int y,int pos,int num)
{
	// if(x == 0)
	x = ++cnt;
	// else
	// 	printf("%d\n",x);
	node[x] = node[y];
	node[x].num += num;
	if(l == r)
		return;
	int mid = l + r>> 1;
	if(pos <= mid)
		build(l,mid,node[x].l,node[y].l,pos,num);
	else
		build(mid + 1, r,node[x].r,node[y].r,pos,num);
}
int query(int l,int r,int x,int y,int t1,int t2,int k)
{
	if(l == r)
		return l;
	int mid = l + r >> 1;
	int s = node[node[x].l].num + node[node[y].l].num - node[node[t1].l].num - node[node[t2].l].num;
	if(k <= s)
	{
		return query(l,mid,node[x].l,node[y].l,node[t1].l,node[t2].l,k);
	}
	else
		return query(mid + 1,r,node[x].r,node[y].r,node[t1].r,node[t2].r,k - s);
}


int dp[maxn][25];
int dep[maxn];
int n,m;
int b[maxn];
int a[maxn];
std::vector<int> vv[maxn];
void dfs(int x,int fa,int de)
{
	dp[x][0] = fa;
	dep[x] = de;
	build(1,m,root[x],root[fa],b[x],1);
	for(int i = 0; i< vv[x].size(); i ++ )
	{
		int v = vv[x][i];
		if(v == fa)
			continue;
		dfs(v,x,de + 1);
	}
}
void init()
{
	for (int i = 1; i <= 19; i ++ )
	{
		for(int k = 1; k <= n; k ++ )
		{
			dp[k][i] = dp[dp[k][i - 1]][i - 1];
		}
	}
}

int getlca(int x,int y)
{
	if(dep[x] < dep[y])
		swap(x,y);
	for (int i = 19; i >= 0; i -- )
	{
		if(dep[dp[x][i]] >= dep[y])
		{
			x = dp[x][i];
		}
	}
	if(x == y)
		return x;
	for(int  i= 19; i >= 0; i -- )
	{
		if(dp[x][i] != dp[y][i])
		{
			x = dp[x][i];
			y = dp[y][i];
		}
	}
	return dp[x][0];
}
std::vector<int> v;

int get_ans(int x,int y,int k)
{
	int t1 = getlca(x,y);

	int t2 = dp[t1][0];
	// printf("%d %d %d %d\n",t1,t2,1,m);
	int ans = query(1,m,root[x],root[y],root[t1],root[t2],k);
	return ans;
}

int main()
{
	// tempwj();	
	int q;
	scanf("%d%d",&n,&q);
	for (int  i=1 ; i <= n; i ++ )
	{
		scanf("%d",&a[i]);
		v.pb(a[i]);
	}
	for(int i =1 ; i< n; i ++ )
	{
		int x,y;
		scanf("%d%d",&x,&y);
		vv[x].pb(y);
		vv[y].pb(x);
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()),v.end());
	m = v.size();
	for(int i = 1; i <= n; i ++ )
	{
		b[i] = lower_bound(v.begin(),v.end(),a[i]) - v.begin() + 1;
	}
	dfs(1,0,1);
	// printf("%d\n",cnt);
	init();
	int ans =0 ;
	while(q -- )
	{
		int x,y,k;
		scanf("%d%d%d",&x,&y,&k);
		// printf("%d\n",ans);
		x ^= ans;
		 // printf("%d %d\n",x,y);
		ans = v[get_ans(x,y,k) - 1];
		printf("%d\n",ans);
	}
}
/*2147468668 1704459667*/

你可能感兴趣的:(做题笔记)