zoukankan      html  css  js  c++  java
  • 树链剖分

    给出一棵 n 个节点的树,初始每个节点有一个点权,要求维护三种操作:
    1 u w:将顶点 u 的权值修改为 w。
    2 u v:询问从 u 到 v 的路径上所有顶点的权值和。
    3 u v:询问从 u 到 v 的路径上最大的权值是多少。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    
    #define ll long long
    #define il inline
    #define db double
    
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    
    using namespace std;
    
    il int gi()
    {
    	int x=0,y=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')
    		{
    			if(ch=='-')
    				y=-1;
    			ch=getchar();
    		}
    	while(ch>='0'&&ch<='9')
    		{
    			x=x*10+ch-'0';
    			ch=getchar();
    		}
    	return x*y;
    }
    
    il ll gl()
    {
    	ll x=0,y=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')
    		{
    			if(ch=='-')
    				y=-1;
    			ch=getchar();
    		}
    	while(ch>='0'&&ch<='9')
    		{
    			x=x*10+ch-'0';
    			ch=getchar();
    		}
    	return x*y;
    }
    
    ll point[100045];//权值
    
    int size[100045];//子树大小
    
    int top[100045];//该链顶
    
    int fa[100045];//爸爸
    
    int son[100045];//重儿子
    
    int deep[100045];//节点深度
    
    int num[100045],tot;//编号
    
    int pos[100045];//编号对应的点
    
    int head[200045],cnt;
    
    struct edge
    {
    	int next,to;
    }e[200045];
    
    il void add(int from,int to)
    {
    	e[++cnt].next=head[from];
    	e[cnt].to=to;
    	head[from]=cnt;
    }
    
    //bool vis[100045];
    
    void dfs1(int x)
    {
    	int r=head[x];
    	size[x]=1;
    	while(r!=-1)
    		{
    			int now=e[r].to;
    			if(now!=fa[x])
    				{
    					deep[now]=deep[x]+1;
    					fa[now]=x;
    					dfs1(now);
    					size[x]+=size[now];
    					if(son[x]==-1||size[now]>size[son[x]])
    						son[x]=now;
    				}
    			r=e[r].next;
    		}
    }
    
    void dfs2(int x,int anc)
    {
    	top[x]=anc;
    	num[x]=++tot;
    	pos[tot]=x;
    	if(son[x]==-1)
    		return;
    	dfs2(son[x],anc);//找重链
    	int r=head[x];
    	while(r!=-1)
    		{
    			int now=e[r].to;
    			if(now!=fa[x]&&now!=son[x])
    				dfs2(now,now);//轻链
    			r=e[r].next;
    		}
    }
    
    struct node
    {
    	ll sum,maxn;
    }c[1000045];
    
    void build(int rt,int l,int r)
    {
    	if(l==r)
    		{
    			c[rt].sum=point[pos[l]];
    			c[rt].maxn=point[pos[l]];
    			return;
    		}
    	if(l>r)
    		return;
       	int mid=(l+r)>>1;
    	build(rt<<1,l,mid);
    	build(rt<<1|1,mid+1,r);
    	c[rt].sum=c[rt<<1].sum+c[rt<<1|1].sum;
    	c[rt].maxn=max(c[rt<<1].maxn,c[rt<<1|1].maxn);
    }
    
    void update(int rt,int l,int r,int pos,ll NUM)
    {
    	if(l==r)
    		{
    			c[rt].sum=NUM;
    			c[rt].maxn=NUM;
    			return;
    		}
    	if(l>r)return;
    	int mid=(l+r)>>1;
    	if(pos<=mid)
    		update(rt<<1,l,mid,pos,NUM);
    	else
    		update(rt<<1|1,mid+1,r,pos,NUM);
    	c[rt].sum=c[rt<<1].sum+c[rt<<1|1].sum;
    	c[rt].maxn=max(c[rt<<1].maxn,c[rt<<1|1].maxn);
    }
    
    ll query(int rt,int l,int r,int L,int R)
    {
    	//if(l>r)
    	//return 0;
    	if(L<=l&&R>=r)
    		return c[rt].sum;
    	if(L>r||R<l)return 0;
    	int mid=(l+r)/2;
    	ll sum=0;
    	if(L<=mid)
    		sum+=query(rt<<1,l,mid,L,R);
    	if(R>mid)
    		sum+=query(rt<<1|1,mid+1,r,L,R);
    	return sum;
    }
    
    ll queryy(int rt,int l,int r,int L,int R)
    {
    	if(L<=l&&R>=r)
    		return c[rt].maxn;
    	int mid=(l+r)>>1;
    	if(L>r||R<l)return -2e9;
    	ll r1=-2e9,r2=-2e9;
    	if(L<=mid)
    		r1=queryy(rt<<1,l,mid,L,R);
    	if(R>mid)
    		r2=queryy(rt<<1|1,mid+1,r,L,R);
    	return max(r1,r2);
    }
    
    int main()
    {
    	freopen("tree.in","r",stdin);
    	freopen("tree.out","w",stdout);
    
    	memset(head,-1,sizeof(head));
    	memset(son,-1,sizeof(son));
    
    	int n=gi();
    
    	for(int i=1;i<=n;i++)
    		point[i]=gl();
    
    	int x,y;
    	for(int i=1;i<n;i++)
    		{
    			x=gi(),y=gi();
    			add(x,y);
    			add(y,x);
    		}
    
    	deep[1]=1;
    	fa[1]=1;
    	dfs1(1);
    
    	dfs2(1,1);
    
    	build(1,1,n);
    
    	int m=gi();
    	int p;
    	for(int i=1;i<=m;i++)
    		{
    			//printf("c[1].sum=%d
    ",c[1].sum);
    			p=gi();
    			if(p==1)
    				{
    					x=gi(),y=gi();
    					update(1,1,n,num[x],y);//点更新
    				}
    			if(p==2)
    				{
    					x=gi(),y=gi();
    					ll sum=0;
    					while(top[x]!=top[y])
    						{
    							if(deep[top[x]]<deep[top[y]])//需要x链顶更深
    								swap(x,y);
    							sum+=query(1,1,n,num[top[x]],num[x]);//加上这一段区间和
    							x=fa[top[x]];//x跳到链顶的爸爸上
    						}
    					if(num[x]<num[y])
    						swap(x,y);
    					sum+=query(1,1,n,num[y],num[x]);//在加上最后一条边
    					printf("%lld
    ",sum);
    				}
    			if(p==3)
    				{
    					x=gi(),y=gi();
    					ll ans=-2e9;
    					while(top[x]!=top[y])
    						{
    							if(deep[top[x]]<deep[top[y]])
    								swap(x,y);
    							ans=max(ans,queryy(1,1,n,num[top[x]],num[x]));
    							x=fa[top[x]];
    						}
    					if(num[x]<num[y])
    						swap(x,y);
    					ans=max(ans,queryy(1,1,n,num[y],num[x]));
    					printf("%lld
    ",ans);
    				}
    		}
    
    	return 0;
    }
    
  • 相关阅读:
    iOS 设置app语言中文,比如 copy中文,拍照按钮cancel 中文
    kCGImagePropertyExifDictionary 引用错误
    Objective-C中3种枚举比较及KVC两个小技巧
    xcode 调试程序 lldb 使用
    iOS kvo 结合 FBKVOController 的使用
    ios 推送app badge 数字累加操作
    推送未找到应用程序的“aps-environment”的权利字符串错误
    AVAudioPlayer播放在线音频文件
    MPMoviePlayerViewController 视频播放黑屏
    PHP 与 Redis 入门教程
  • 原文地址:https://www.cnblogs.com/gshdyjz/p/7701602.html
Copyright © 2011-2022 走看看