数据结构day2 lca

丁叔叔的恐怖红包

小庆住在一个很特别的国度里,它有N 个城市,并且只建了N ?1 条双向路,但神奇的是任意两个城市
都可以通过这些路连接起来。小庆最近在研究寒假的旅游计划,有时她想快速地知道两个城市之间的距
离,于是找你来帮帮解决。
Input
第1 行一个整数N。
接下来N ? 1 行,每行三个整数u; v;w,表示城市u 和城市v 之间有一条长为w 的路。
接下来1 行,包含一个整数Q,表示小庆有Q 个询问。
接下来Q 行,每行两个整数u; v,表示小庆想知道u 和v 这两个城市之间的距离。
Output
对于小庆的每个询问,输出两个城市之间的距离。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200005;
const int p=20;
int wi[maxn],dep[maxn],dis[maxn],pos[maxn],nxt[maxn],tov[maxn],head[maxn],anc[maxn][p+1];
int q,n,tot=0,root;
void add(int i,int j,int w)
{
	tot++;
	tov[tot]=j;
	nxt[tot]=head[i];
	wi[tot]=w;
	head[i]=tot;
}
void dfs(int u,int f)
{
	anc[u][0]=f;
	for (int i=1;i<=p;i++)
	   anc[u][i]=anc[anc[u][i-1]][i-1];
	for (int i=head[u];i;i=nxt[i])
	{
		int v=tov[i];
		if (v==f)
		continue;
		dep[v]=dep[u]+1;
		dis[v]=dis[u]+wi[i];
		dfs(v,u);
	}
}
int lca(int u,int v)
{
	if (dep[u]<dep[v])
	swap(u,v);
	int t=dep[u]-dep[v];
	for (int i=0;t;t>>=1,i++){
		if (t&1)
	      u=anc[u][i];
	    }if (u==v)
	    return u;//惨痛教训 
	for (int i=p;anc[u][0]!=anc[v][0];i--)
	  if (anc[u][i]!=anc[v][i])
	  {
	  	u=anc[u][i];
	  	v=anc[v][i];
	  }
	return anc[u][0];
}
int main()
{
	freopen("distance.in","r",stdin);
	freopen("distance.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n-1;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
		add(v,u,w);
	}
    dep[1]=1;
    dis[1]=0;
	dfs(1,1);
	scanf("%d",&q);
    for (int i=1;i<=q;i++)
    {
    	int x,y,ans=0;
    	scanf("%d%d",&x,&y);
    	int lca1=lca(x,y);
    	printf("%d\n",dis[x]+dis[y]-2*dis[lca1]);
    }
    return 0;
}
/*
4
1 2 3
1 3 4
2 4 2
3
1 1
1 4
2 3
*/
(承上题)小漫是小庆那个国家的国王,她住在1 号城市,u 号城市如果到1 必定经过v 号城市,我们则
称v 号城市管辖u 号城市(v 号城市也管辖自己)。过年了,小漫想给国家的一些城市发红包,每次她会
给u 号城市管辖的每个城市发放w 的红包,有时,她也想知道某个城市或被某个城市管辖的城市一共得
了多少红包。如下:
• give u w :表示将u 号城市管辖的每个城市发w 的红包。
• single u :表示询问u 号城市得了多少红包。
• all u :表示询问u 号城市管辖的城市一共得了多少红包。
Input
第1 行一个整数N。
接下来N ? 1 行,每行三个整数u; v,表示城市u 和城市v 之间有一条路。
接下来1 行,包含一个整数Q,表示小漫有Q 个操作。
接下来Q 行,每行是上面三种操作的一种。
Output
对每个询问,输出其答案。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=200005;

int flag[N*2],out[N],in[N],tot,dd,tov[N],head[N],nex[N];
long long f[N*2],tag[N*2];
char s1[15];
void add(int x,int y)
{
	tot++;
	tov[tot]=y;
	nex[tot]=head[x];
	head[x]=tot;
}
void dfs(int u,int f)
{
	dd++;
	in[u]=dd;
	for(int i=head[u];i;i=nex[i])
        {
        	int v=tov[i];
        	if(v==f) continue;
        	dfs(v,u);
        }
    out[u]=dd;
}
void update(int o)
{
	f[o]=f[o*2]+f[o*2+1];
}
void push_down(int o,int l,int r)
{
	int mid=(l+r)/2;
	if(flag[o]==1)
	{
		f[o*2]+=(mid-l+1)*tag[o];
		f[o*2+1]+=(r-mid)*tag[o];
		tag[o*2]+=tag[o];
		tag[o*2+1]+=tag[o];
	    flag[o*2]=1;
		flag[o*2+1]=1;
	    tag[o]=flag[o]=0;
	}
}
long long query(int o,int l,int r,const int L,const int R)
{
	if(L<=l&&R>=r)
	  return f[o];
	push_down(o,l,r);
	int mid=(r+l)/2;
	long long ans=0;
	if(L<=mid) ans+=query(o*2,l,mid,L,R);
    if(R>mid) ans+=query(o*2+1,mid+1,r,L,R);
    return ans;
}
void change(int o,int l,int r,const int L,const int R,long long data)
{
	if(L<=l&&R>=r)
	{
	 f[o]+=data*(r-l+1);
	 tag[o]+=data;
		flag[o]=1;
		return;
	}
	push_down(o,l,r);
	int mid=(l+r)/2;
	if(L<=mid) change(o*2,l,mid,L,R,data);
    if(R>mid) change(o*2+1,mid+1,r,L,R,data);
    update(o);
}
int main()
{
	freopen("redpacket.in","r",stdin);
	freopen("redpacket.out","w",stdout);
	int m,n,y,x;
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	scanf("%d",&m);
	dfs(1,1);
	for(int i=1;i<=m;i++)
	  {
	  	scanf("%s",s1);
	  	if(s1[0]=='g')
	  	{
	  	  scanf("%d%d",&x,&y);
	  	  change(1,1,n,in[x],out[x],y);
	  	}
	    if(s1[0]=='s')
	    {
		    scanf("%d",&x);
	    	long long la=query(1,1,n,in[x],out[x]);  
	    	if(in[x]==out[x])
	    	{
			printf("%I64d\n",la);
	    	}	
	    	else
	    	{   
	    	long long ans;
	    		long long la2=query(1,1,n,in[x]+1,out[x]);
	    		ans=la-la2;
	    	    printf("%I64d\n",ans);
	    	}
	    }
	    if(s1[0]=='a')
	    {
	    	scanf("%d",&x);
	    	long long la=query(1,1,n,in[x],out[x]);
	    	printf("%I64d\n",la);
	    }
	  }
	  return 0;
}
/*
5
1 2
1 3
2 4
2 5
3
give 1 5
single 2
all 2
*/
(承上题)小漫觉得那样发红包有些无聊,于是决定每次给u 号城市到v 号城市简单路径经过的城市发
红包(当然包括u 和v 本身),考虑到你们还太年轻,就只问你们单个城市的红包了:
• give u v w :给u 到v 的简单路径上的城市w 的红包
• single u :询问到目前为止u 号城市得到的红包
Input
第1 行一个整数N。
接下来N ? 1 行,每行三个整数u; v,表示城市u 和城市v 之间有一条路。
接下来1 行,包含一个整数Q,表示小漫有Q 个操作。
接下来Q 行,每行是上面两个操作中的一个。
Output
对于每个询问,输出其答案。

跑一波std指针

#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 100010;
const int M = N + N;
const int P = 16;

struct Node {
	long long sum;
	Node *ls, *rs;
	void update() {
		sum = ls->sum + rs->sum;
	}
}pool[N*3], *tail=pool, *root;

int n, q;
int head[N], dest[M], last[M], etot;
int in[N], out[N], seq[N], dep[N], anc[N][P+1], idc;

void adde( int u, int v ) {
	etot++;
	dest[etot] = v;
	last[etot] = head[u];
	head[u] = etot;
}
void dfs( int u, int f ) {
	seq[++idc] = u;
	in[u] = idc;
	anc[u][0] = f;
	for( int p = 1; p <= P; p++ )
		anc[u][p] = anc[anc[u][p-1]][p-1];
	for( int t = head[u]; t; t = last[t] ) {
		int v = dest[t];
		if( v == f ) continue;
		dep[v] = dep[u] + 1;  // idy!!!!!!!!! I'm angry!!!
		dfs( v, u );
	}
	out[u] = idc;
}
int lca( int u, int v ) {
	if( dep[u] < dep[v] ) swap(u,v);
	int t = dep[u] - dep[v];
	for( int p = 0; t; t>>=1, p++ )
		if( t & 1 ) u = anc[u][p];
	if( u == v ) return u;
	for( int p = P; anc[u][0] != anc[v][0]; p-- )
		if( anc[u][p] != anc[v][p] )
			u = anc[u][p], v = anc[v][p];
	return anc[u][0];
}
Node *build( int lf, int rg ) {
	Node *nd = ++tail;
	if( lf == rg ) {
		nd->sum = 0;
	} else {
		int mid = (lf + rg) >> 1;
		nd->ls = build( lf, mid );
		nd->rs = build( mid+1, rg );
		nd->sum = 0;
	}
	return nd;
}
long long query( Node *nd, int lf, int rg, int L, int R ) {
	if( L <= lf && rg <= R ) 
		return nd->sum;
	int mid = (lf + rg) >> 1;
	long long rt = 0;
	if( L <= mid )
		rt += query( nd->ls, lf, mid, L, R );
	if( R > mid )
		rt += query( nd->rs, mid + 1, rg, L, R );
	return rt;
}
void modify( Node *nd, int lf, int rg, int pos, int delta ) {
	if( lf == rg ) {
		nd->sum += delta;
		return;
	}
	int mid = (lf + rg)>>1;
	if( pos <= mid )
		modify( nd->ls, lf, mid, pos, delta );
	else
		modify( nd->rs, mid+1, rg, pos, delta );
	nd->update();
}
int main() {
	freopen ( "redpacket2.in", "r", stdin ) ;
	freopen ( "redpacket2.out", "w", stdout ) ;
	scanf( "%d", &n );
	for( int i = 1; i < n; i++ ) {
		int u, v;
		scanf( "%d%d", &u, &v );
		adde( u, v );
		adde( v, u );
	}
	idc = 0;
	dep[1] = 1;
	dfs( 1, 1 );
	root = build( 1, idc );
	scanf( "%d", &q );
	while( q-- ) {
		char ss[100];
		int u, v, w;
		scanf( "%s", ss );
		if( ss[0] == 'g' ) {
			scanf( "%d%d%d", &u, &v, &w );
			int ca = lca(u,v);
			modify( root, 1, idc, in[u], w );
			modify( root, 1, idc, in[v], w );
			modify( root, 1, idc, in[ca], -w );
			if( ca != 1 )
				modify( root, 1, idc, in[anc[ca][0]], -w );
		} else {
			scanf( "%d", &u );
			printf( "%lld\n", query(root,1,idc,in[u],out[u]) );
		}
	}
}
lca版子记错爆0异常难受


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值