SNOI省选模拟赛 dat1t3 tree

题意:给定一棵n个点、n-1条边的树,树上的第i条边有权值w[i] 。

      q次询问,每次询问为下列两种操作之一:

      1:增加一个点对 x,y。    

           2:查询第x条边权值为y时所有点对之间的距离的最大值。

题解:还没完全想清楚,先占个坑,最近来补。

下附暂时没有想清的AC的代码...

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define lson (now<<1)
#define rson ((now<<1)|1)
#define mid ((nl+nr)>>1)
#define maxn 100005
using namespace std;
int root,mod,q;
int n,cnt,tot=1,top;
int head[maxn],nex[maxn<<1],val[maxn<<1],to[maxn<<1];
void add(int x,int y,int z)
{
	to[++tot]=y;val[tot]=z;nex[tot]=head[x];head[x]=tot;
}

//以下为线段树
pair<int,int> dat[maxn<<2];
void update(int ql,int qr,int add,int nl,int nr,int now,int op)
{
	if(ql>qr) return;
	if(ql<=nl && nr<=qr)
	{
		if(op)
		dat[now].second=max(dat[now].second,add);
		else
		dat[now].first=max(dat[now].first,add);
		return;
	}
	if(ql<=mid) update(ql,qr,add,nl,mid,lson,op);
	if(mid<qr)  update(ql,qr,add,mid+1,nr,rson,op);
}

pair<int,int> query(int pos,int nl,int nr,int now)
{
	if(nl==nr) return dat[now];
	pair<int,int> ans;
	if(pos<=mid) ans=query(pos,nl,mid,lson);
	else ans=query(pos,mid+1,nr,rson);
	ans.first=max(ans.first,dat[now].first);
	ans.second=max(ans.second,dat[now].second);
	return ans;
}

//以下为树链剖分 
int dfn[maxn],dis[maxn],fa[maxn][30],bel[maxn<<1];
int siz[maxn],anc[maxn],dep[maxn],in[maxn],out[maxn];
void dfs1(int now,int pa)
{
	siz[now]=1; dep[now]=dep[pa]+1; fa[now][0]=pa;
	for(int i=1;i<=29;i++)	fa[now][i]=fa[fa[now][i-1]][i-1];
	for(int i=head[now];i;i=nex[i])
	if(to[i]!=pa)
	{
		dis[to[i]]=dis[now]+val[i];
		bel[i>>1]=to[i];
		dfs1(to[i],now);
		siz[now]+=siz[to[i]];
	}
}

void dfs2(int now,int pa)
{
	dfn[now]=++cnt;in[now]=cnt;out[now]=cnt;
	anc[now]=pa;
	int son=0;
	for(int i=head[now];i;i=nex[i])
		if(to[i]!=fa[now][0] && siz[to[i]]>siz[son])
			son=to[i];
	if(son==0) return;
	dfs2(son,pa);
	for(int i=head[now];i;i=nex[i])
	if(to[i]!=fa[now][0] && to[i]!=son)
	dfs2(to[i],to[i]);
	out[now]=cnt;
}

int lca(int p,int q)
{
	while(anc[p]!=anc[q])
	{
		if(dep[anc[p]]<dep[anc[q]])	q=fa[anc[q]][0];
		else p=fa[anc[p]][0];
	}
	if(dep[p]<dep[q]) return p;
	else return q;
}

void update(int p,int q,int z)
{
	while(anc[p]!=anc[q])
	{
		update(dfn[anc[p]],dfn[p],z,1,n,1,0);
		update(out[p]+1,out[anc[p]],z,1,n,1,1);
		int temp=fa[anc[p]][0];
		update(dfn[temp]+1,dfn[anc[p]]-1,z,1,n,1,1);
		update(out[p]+1,out[temp],z,1,n,1,1);
		p=temp;
	}
	update(dfn[q],dfn[p],z,1,n,1,0);
	if(out[p]!=out[q])
	update(out[p]+1,out[q],z,1,n,1,1);
}

//以下为主要函数 
int getson(int x,int d)
{
	for (int i=0;i<20 && d;++i,d>>=1) if (d&1)  x=fa[x][i];
	return x;
}

void add(int x,int y)
{
	if(x==y) return;
	if(dep[x]>dep[y]) swap(x,y);
	int l=lca(x,y),len=dis[x]+dis[y]-(dis[l]*2);
	printf("%d\n",len);
	
	int px=getson(x,dep[x]-dep[l]-1),py=getson(y,dep[y]-dep[l]-1);
	
	if(x!=l) update(x,px,len); 
	
	update(y,py,len);
	
	if(dfn[l]>1) update(1,dfn[l]-1,len,1,n,1,1);
	if(out[l]<n) update(out[l]+1,n,len,1,n,1,1);
	
	if(x!=l && dfn[x]!=out[x]) update(dfn[x]+1,out[x],len,1,n,1,1);
	if(dfn[y]!=out[y]) update(dfn[y]+1,out[y],len,1,n,1,1);
	
	if (dfn[px]>dfn[py]) swap(px,py);
	if (x!=l) 
	{
		update(dfn[l],dfn[px]-1,len,1,n,1,1);
		update(out[px]+1,dfn[py]-1,len,1,n,1,1);
		update(out[py]+1,out[l],len,1,n,1,1);
	}
	else 
	{
		update(dfn[l],dfn[py]-1,len,1,n,1,1);
		update(out[py]+1,out[l],len,1,n,1,1);
	}
}

void query2(int x,int y)
{
	pair<int,int> res=query(dfn[bel[x]],1,n,1);
	if(res.first && res.second) printf("%d\n",max(res.first-val[x*2]+y,res.second));
	else if(res.first) printf("%d\n",res.first-val[x*2]+y);
	else printf("%d\n",res.second);
}
int main()
{
	scanf("%d%d",&n,&q);
	for(int i=1;i<n;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);add(y,x,z);
	}
	dfs1(1,0);
	dfs2(1,1);
	while(q--)
	{
		int op,x,y;
		scanf("%d%d%d",&op,&x,&y);
		if(op==1) add(x,y);
		else query2(x,y);
	} 
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值