1. 程式人生 > 其它 >CSUST 遞增陣列2 題解(思維+分段考慮)

CSUST 遞增陣列2 題解(思維+分段考慮)

一定要保護自己的夢想,即使犧牲一切。

我們可以思考怎麼做呢。
首先我們需要進行一些分類討論:
我們先思考一下如果所有關鍵點都在 \(p\) 的子樹內,
那顯然是所有關鍵點的 \(Lca\)\(p\) 距離。
如果所有關鍵點一些在 \(p\) 的子樹裡,一些在子樹外,則答案顯然為 \(0\)
那我們只需要接著討論一下所有關鍵點在都在子樹外的情況即可。
我們知道一個點一定會沿著祖先往下走,然後在往一個子樹進入。
如果關鍵點全都是在祖先的一個子樹內,那答案一定是這些關鍵點的 \(Lca\)\(p\) 的距離。
否則這個答案一定是到祖先的鏈上的某個點,這個點滿足是這個子樹裡沒有關鍵點且是最淺的點。
區間 \(Lca\) 可以使用線段樹解決,然後我們在 \(dfn\)

序上做一個主席樹的操作,然後就可以查詢子樹內的點的情況了。

// code by fhq_treap
#include<bits/stdc++.h>
#define ll int
#define N 300005

inline ll read(){
    char C=getchar();
    ll A=0 , F=1;
    while(('0' > C || C > '9') && (C != '-')) C=getchar();
    if(C == '-') F=-1 , C=getchar();
    while('0' <= C && C <= '9') A=(A << 1)+(A << 3)+(C - 48) , C=getchar();
    return A*F;
}

template <typename T>
void write(T x)
{
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    if(x > 9)
        write(x/10);
    putchar(x % 10 + '0');
    return;
}

ll n,q;
ll head[N],cnt;
struct P{
	int to,next,w;
}e[N << 1];
inline void add(int x,int y,int w){
e[++cnt].to = y,e[cnt].next = head[x],e[cnt].w = w,head[x] = cnt;
}

//tree

ll dfn[N],s[N],inv[N];
ll dfncnt;
int fa[N][30],dep[N],end[N];
inline void dfs(int x,int f){
	end[x] = dfn[x] = ++dfncnt;
	dep[x] = dep[f] + 1;
	inv[dfncnt] = x;
	fa[x][0] = f;
	for(int i = 1;i < 30;i ++)
	fa[x][i] = fa[fa[x][i - 1]][i - 1];
	for(int i = head[x];i;i = e[i].next){
		int v = e[i].to;
		if(v == f)continue;
		s[v] = s[x] + e[i].w;
		dfs(v,x);
		end[x] = std::max(end[x],end[v]);
	}
}

inline ll lca(ll x,ll y){
	if(dep[y] > dep[x])
	std::swap(x,y);
	for(int i = 29;i >= 0;--i){
		if(dep[fa[x][i]] >= dep[y])
		x = fa[x][i];
	}
	if(x == y)
	return x;
	for(int i = 29;i >= 0;--i){
		if(fa[x][i] != fa[y][i])
		x = fa[x][i],y = fa[y][i];
	}
	return fa[x][0];
}

ll T[N << 2];

#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
#define mid ((l + r) >> 1)
#define root 1,1,n

inline void build(int u,int l,int r){
	if(l == r){
		T[u] = l;·1全額日圖與i哦怕【-】
		return ;
	}
	build(ls(u),l,mid);
	build(rs(u),mid + 1,r);
	T[u] = lca(T[ls(u)],T[rs(u)]);
	return ;
}

inline ll qlca(int u,int l,int r,int tl,int tr){
	if(tl <= l && r <= tr)
	return T[u];
	ll li,ri;li = ri = 0;
	if(tl <= mid)
	li = qlca(ls(u),l,mid,tl,tr);
	if(tr > mid)
	ri = qlca(rs(u),mid + 1,r,tl,tr);
	return (li && ri) ? lca(li,ri) : li + ri;
}

//dfn_lca

int H[N * 40];
int Hcnt;
int Head[N],Ls[N * 40],Rs[N * 40];
inline void merge(int las,int &now,int p,int l,int r){
	if(!now)now = ++Hcnt;
	Ls[now] = Ls[las];
	Rs[now] = Rs[las];
	H[now] = H[las] + 1;
	if(l == r)
	return ;
	if(p <= mid){
		Ls[now] = 0;
		merge(Ls[las],Ls[now],p,l,mid);
	}
	if(p > mid){
		Rs[now] = 0;
		merge(Rs[las],Rs[now],p,mid + 1,r);
	}
}

inline ll find(int las,int now,int l,int r,int tl,int tr){
	if(tl <= l && r <= tr)
	return H[now] - H[las];
	ll ans = 0;
	if(tl <= mid)
	ans += find(Ls[las],Ls[now],l,mid,tl,tr);
	if(tr > mid)
	ans += find(Rs[las],Rs[now],mid + 1,r,tl,tr);
	return ans;
}

//主席樹

ll las = 0;

inline void solve(ll now,ll l,ll r){
	ll num = find(Head[dfn[now] - 1],Head[end[now]],1,n,l,r);
	if(num == (r - l + 1)){
		las = s[qlca(root,l,r)] - s[now];
		std::cout<<las<<std::endl;
	}else{
		if(num != 0){
			std::cout<<(las = 0)<<std::endl;
			return ;
		}
		ll x = now;
		for(int i = 29;i >= 0;--i){
			int p = fa[x][i];
			if(p != 0){
				if(!(find(Head[dfn[p] - 1],Head[end[p]],1,n,l,r)))
				x = fa[x][i];
			}
		}
		if(fa[x][0] != 0 && !(find(Head[dfn[fa[x][0]] - 1],Head[end[fa[x][0]]],1,n,l,r)))
		x = fa[x][0];
		x = fa[x][0];
		ll L1 = qlca(root,l,r);ll L2 = lca(now,L1);
		if(L1 == L2)
		las = s[now] - s[x];
		else
		las = s[now] - 2 * s[L2] + s[L1];
		std::cout<<las<<std::endl;
		return ;
	}
}

int main(){
	scanf("%d%d",&n,&q);
	for(int i = 1;i < n;++i){
		ll x,y,w;
		scanf("%d%d%d",&x,&y,&w);
		add(x,y,w);
		add(y,x,w);
	}
	dfs(1,0);
	build(root);
	for(int i = 1;i <= n;++i)
		merge(Head[i - 1],Head[i],inv[i],1,n);
	while(q -- ){
		ll p,l,r;
		scanf("%d%d%d",&p,&l,&r);
		p ^= las;
		l ^= las;
		r ^= las;
		solve(p,l,r);
	}
}