• BZOJ1036 [ZJOI2008]树的统计Count 树链剖分


    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ1036


    题意概括

      一个树,每个节点有一个权值。3种操作。

      1:修改某一个节点的权值。

      2:询问某两个节点间的权值和

      3:询问某两个节点之间的最大权值。


    题解

      树链剖分裸题


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=30005,Inf=33333;
    struct Edge{
    	int cnt,y[N*2],nxt[N*2],fst[N];
    	void clear(){
    		cnt=0;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b){
    		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
    	}
    }g;
    int n,m,v[N],fa[N],size[N],son[N],depth[N],top[N],p[N],ap[N],cnp;
    struct Tree{
    	int m,s;
    }t[N*4];
    void Get_Gen_Info(int rt,int pre,int d){
    	depth[rt]=d,size[rt]=1,fa[rt]=pre,son[rt]=-1;
    	for (int i=g.fst[rt];i;i=g.nxt[i])
    		if (g.y[i]!=pre){
    			int s=g.y[i];
    			Get_Gen_Info(s,rt,d+1);
    			size[rt]+=size[s];
    			if (son[rt]==-1||size[s]>size[son[rt]])
    				son[rt]=s;
    		}
    }
    void Get_Pos(int rt,int tp){
    	top[rt]=tp,p[rt]=++cnp,ap[cnp]=rt;
    	if (son[rt]==-1)
    		return;
    	else
    		Get_Pos(son[rt],tp);
    	for (int i=g.fst[rt];i;i=g.nxt[i]){
    		int s=g.y[i];
    		if (s!=fa[rt]&&s!=son[rt])	
    			Get_Pos(s,s);
    	}
    }
    void pushup(int rt){
    	int ls=rt<<1,rs=ls|1;
    	t[rt].m=max(t[ls].m,t[rs].m);
    	t[rt].s=t[ls].s+t[rs].s;
    }
    void build(int rt,int le,int ri){
    	if (le==ri){
    		t[rt].m=t[rt].s=v[ap[le]];
    		return;
    	}
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	build(ls,le,mid);
    	build(rs,mid+1,ri);
    	pushup(rt);
    }
    void change(int rt,int le,int ri,int pos,int v){
    	if (le==ri){
    		t[rt].m=t[rt].s=v;
    		return;
    	}
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	if (pos<=mid)
    		change(ls,le,mid,pos,v);
    	else
    		change(rs,mid+1,ri,pos,v);
    	pushup(rt);
    }
    int query(int rt,int le,int ri,int xle,int xri,int ty){
    	if (le>xri||ri<xle)
    		return ty?0:-Inf;
    	if (xle<=le&&ri<=xri)
    		return ty?t[rt].s:t[rt].m;
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	if (ty)
    		return query(ls,le,mid,xle,xri,ty)+query(rs,mid+1,ri,xle,xri,ty);
    	else
    		return max(query(ls,le,mid,xle,xri,ty),query(rs,mid+1,ri,xle,xri,ty));
    }
    int find(int a,int b,int t){
    	int f1=top[a],f2=top[b],ans=t?0:-Inf;
    	while (f1!=f2){
    		if (depth[f1]<depth[f2])
    			swap(f1,f2),swap(a,b);
    		if (t)
    			ans+=query(1,1,n,p[f1],p[a],t);
    		else
    			ans=max(ans,query(1,1,n,p[f1],p[a],t));
    		a=fa[f1],f1=top[a];
    	}
    	if (depth[a]>depth[b])
    		swap(a,b);
    	if (t)
    		ans+=query(1,1,n,p[a],p[b],t);
    	else
    		ans=max(ans,query(1,1,n,p[a],p[b],t));
    	return ans;
    }
    int main(){
    	scanf("%d",&n);
    	g.clear();
    	for (int i=1,a,b;i<n;i++){
    		scanf("%d%d",&a,&b);
    		g.add(a,b);
    		g.add(b,a);
    	}
    	for (int i=1;i<=n;i++)
    		scanf("%d",&v[i]);
    	cnp=0;
    	Get_Gen_Info(1,0,0);
    	Get_Pos(1,1);
    	build(1,1,n);
    	scanf("%d",&m);
    	for (int i=1;i<=m;i++){
    		char str[10];
    		int a,b,t;
    		scanf("%s%d%d",str,&a,&b);
    		if (str[0]=='C')
    			change(1,1,n,p[a],b);
    		else {
    			t=str[1]=='M'?0:1;
    			printf("%d
    ",find(a,b,t));
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    面试题58 二叉树的下一个结点
    面试题57 删除链表中重复的结点
    面试题56 链表中环的入口结点
    面试题55 字符流中第一个不重复的字符
    面试题54 表示数值的字符串
    面试题50 树中两个结点的最低公共祖先
    面试题53 正则表达式匹配
    面试题52 构建乘积数组
    面试题51 数组中重复的数字
    Qt链接库出错version Qt_5 not defined
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1036.html
Copyright © 2020-2023  润新知