BZOJ 3251: 树上三角形

39 篇文章 0 订阅
24 篇文章 0 订阅

题目

题解:
这是一个判定性问题。
&gt; 47 &gt;47 >47个点就必定有解。可以通过较小两边之和<=第三边来证明。
然后就暴力往上跳存下来暴力判断就行了。

树剖AC Code:

#include<bits/stdc++.h>
#define maxn 400005
#define pb push_back
#define lc u<<1
#define rc u<<1|1
#define lim 55
using namespace std;

int n,q;
int ar[maxn][lim],a[maxn];

vector<int>G[maxn];

int dep[maxn],tp[maxn],fa[maxn],siz[maxn],son[maxn],id[maxn],pos[maxn],tot;
void dfs(int u,int ff){
	dep[u] = dep[fa[u] = ff] + (siz[u] = 1);
	for(int i=0,v;i<G[u].size();i++)
		if((v=G[u][i]) != ff){
			dfs(v,u);
			siz[u] += siz[v];
			if(siz[v] > siz[son[u]])
				son[u] = v;
		}
}

void dfs2(int u,int ff){
	pos[id[u] = ++tot] = u;
	if(son[u]) tp[son[u]] = tp[u] , dfs2(son[u] , u);
	for(int i=0,v;i<G[u].size();i++)
		if((v=G[u][i]) != ff && v!=son[u]){	
			tp[v] = v,dfs2(v,u);
		}
}

int tmp[lim];
void merge(int *a,int *b,int *c){
	int i = 0 , j = 0 , k = 0;
	memset(tmp,-0x3f,sizeof tmp);
	for(;i<lim && j<lim && k<lim && (a[i]>0 || b[j]>0);)
		if(a[i] < b[j]) tmp[k++] = b[j++];
		else tmp[k++] = a[i++];
	for(i=0;i<lim;i++)
		c[i] = tmp[i];
}

void upd(const int &u){
	merge(ar[lc],ar[rc],ar[u]);
}

void Build(int u,int l,int r){
	if(l == r){
		ar[u][0] = a[pos[l]];
		return;
	}
	int mid  = (l+r) >> 1;
	Build(lc,l,mid),Build(rc,mid+1,r);
	upd(u);
}

void Insert(int u,int l,int r,int pos,int v){
	if(l == r){
		ar[u][0] = v;
		return;
	}
	int mid = (l+r) >> 1;
	if(pos <= mid) Insert(lc,l,mid,pos,v);
	else Insert(rc,mid+1,r,pos,v);
	upd(u);
}

void Query(int u,int l,int r,int ql,int qr,int *c){
	if(ql > r || l > qr) return;
	if(ql <= l && r <= qr){
		merge(c,ar[u],c);
		return;
	}
	int mid = (l+r) >> 1;
	Query(lc,l,mid,ql,qr,c),Query(rc,mid+1,r,ql,qr,c);
}

int rt[60];

int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<n;i++){
		int a,b;scanf("%d%d",&a,&b);
		G[a].pb(b),G[b].pb(a);
	}
	dfs(1,0),tp[1]=1,dfs2(1,0);
	memset(ar,-0x3f,sizeof ar);
	Build(1,1,n);
	for(int t,a,b;q--;){
		scanf("%d%d%d",&t,&a,&b);
		if(t == 0){
			memset(rt,-0x3f,sizeof rt);
			for(;tp[a]!=tp[b];){
				if(dep[tp[a]] < dep[tp[b]]) swap(a,b);
				Query(1,1,n,id[tp[a]],id[a],rt);
				a = fa[tp[a]];
			}
			Query(1,1,n,min(id[a],id[b]),max(id[a],id[b]),rt);
			bool flg = 0;
			for(int i=0;i+2<lim && rt[i+2] > 0;i++)
				if(1ll * rt[i+2] + 1ll * rt[i+1] > rt[i]){
					flg = 1;
					break;
				}
			if(flg)
				puts("Y");
			else 
				puts("N");
		}
		else{
			Insert(1,1,n,id[a],b);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值