[xsy1019]小A学树论

题意:维护一棵带点权的树,支持查询子树权值和,子树整体增值,换父亲

复习splay

刚开始做的时候智障了,这道题其实直接用splay维护出栈入栈序列就好了

#include<stdio.h>
struct edge{
	int to,nex;
}e[200010];
#define ll long long
int fa[200010],ch[200010][2],siz[200010],nv[100010],h[100010],in[100010],out[100010],M,rt,tot;
ll v[200010],ad[200010],sum[200010];
#define ls ch[x][0]
#define rs ch[x][1]
void add(int a,int b){
	tot++;
	e[tot].to=b;
	e[tot].nex=h[a];
	h[a]=tot;
}
void dfs(int f,int x){
	in[x]=++M;
	for(int i=h[x];i;i=e[i].nex){
		if(e[i].to!=f)dfs(x,e[i].to);
	}
	out[x]=++M;
}
void pushup(int x){
	sum[x]=v[x]+sum[ls]+sum[rs];
	siz[x]=siz[ls]+siz[rs]+1;
}
int build(int l,int r){
	int mid=(l+r)>>1;
	if(l<mid){
		ch[mid][0]=build(l,mid-1);
		fa[ch[mid][0]]=mid;
	}
	if(mid<r){
		ch[mid][1]=build(mid+1,r);
		fa[ch[mid][1]]=mid;
	}
	pushup(mid);
	return mid;
}
void rot(int x){
	int y,z,f,B;
	y=fa[x];
	z=fa[y];
	if(y==rt)rt=x;
	f=ch[y][0]==x;
	B=ch[x][f];
	fa[x]=z;
	fa[y]=x;
	if(B)fa[B]=y;
	ch[x][f]=y;
	ch[y][f^1]=B;
	if(ch[z][0]==y)ch[z][0]=x;
	if(ch[z][1]==y)ch[z][1]=x;
	pushup(y);
	pushup(x);
}
void plus(int x,ll d){
	sum[x]+=siz[x]*d;
	ad[x]+=d;
	v[x]+=d;
}
void pushdown(int x){
	if(ad[x]){
		if(ls)plus(ls,ad[x]);
		if(rs)plus(rs,ad[x]);
		ad[x]=0;
	}
}
void gao(int x){
	if(fa[x])gao(fa[x]);
	pushdown(x);
}
void splay(int x,int gl){
	gao(x);
	int y,z;
	while(fa[x]!=gl){
		y=fa[x];
		z=fa[y];
		if(z!=gl)rot((ch[z][0]==y&&ch[y][0]==x)||(ch[z][1]==y&&ch[y][1]==x)?y:x);
		rot(x);
	}
}
int presc(int x){
	splay(x,0);
	x=ls;
	while(rs)x=rs;
	return x;
}
int nexsc(int x){
	splay(x,0);
	x=rs;
	while(ls)x=ls;
	return x;
}
int sub(int x){
	int p=presc(in[x]),n=nexsc(out[x]);
	if(p==0){
		if(n==0)return rt;
		splay(n,0);
		return ch[n][0];
	}
	splay(p,0);
	if(n==0)return ch[p][1];
	splay(n,p);
	return ch[n][0];
}
ll query(int x){return sum[sub(x)]>>1;}
void modify(int x,ll v){plus(sub(x),v);}
void change(int x,int y){
	int s=sub(x);
	x=fa[s];
	if(ls==s)ls=0;
	if(rs==s)rs=0;
	while(x){
		pushup(x);
		x=fa[x];
	}
	x=nexsc(in[y]);
	splay(x,in[y]);
	fa[s]=x;
	ls=s;
	while(x){
		pushup(x);
		x=fa[x];
	}
}
int main(){
	int n,m,i,x,y;
	ll d;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%d",nv+i);
	for(i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs(0,1);
	for(i=1;i<=n;i++)v[in[i]]=v[out[i]]=nv[i];
	rt=build(1,M);
	while(m--){
		scanf("%d",&i);
		if(i==1){
			scanf("%d",&x);
			printf("%lld\n",query(x));
		}
		if(i==2){
			scanf("%d%lld",&x,&d);
			modify(x,d);
		}
		if(i==3){
			scanf("%d%d",&x,&y);
			change(x,y);
		}
	}
}
时间: 2024-10-15 23:55:07

[xsy1019]小A学树论的相关文章

[XSY 1019] 小A学树论 Splay维护入栈出栈序

题意 给定一棵 n 个节点的树. 这棵树以 1 为根, 每个点有点权. 在树上支持三种操作: ① 查询以 x 为根的子树的点权之和; ② 将以 x 为根的子树中的每个点的点权增加 w ; ③ 将 以 x 为根的子树转移到 y 的直接后继. $n \le 100000$ . 实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #includ

LCA(倍增在线算法) codevs 2370 小机房的树

codevs 2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计

小故事学设计模式之Decorate: (二)老婆的新衣服

老婆有一件蓝色的裙子和一件粉色的裙子, 不管怎么穿,她还是原来的老婆. 但是在软件里就不一定了, 如果把老婆比作一个class的话, 有一种做法是会因为增加了两个新的Property而继承出两个子类: "穿裙子的老婆, 穿粉色上衣的老婆". 你这样弄出两个子类也没什么不对, 问题是当MM的有上百件服装的时候,就会产生上百个子类,这个不好,将来万一父类一变化,下面上百个子类都要一个个地去修改,太乱了. 有一个更合理的方式来解决这个"老婆的装饰问题".我们的要求是:  

积累的VC编程小技巧之树操作

1.如何在TreeList中加图标? [问题提出]  请问treeview控件和treectrl控件的用法有何不同呢?向如何imagelist控件中加图象呀?  [解决方法]  1)    HICON hicon[8];    m_imageList.Create(16,16,0,8,8);    hicon[0]=AfxGetApp()->LoadIcon(IDI_ICON0);    hicon[1]=AfxGetApp()->LoadIcon(IDI_ICON1);    hicon[2

codevs 2370 小机房的树

2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到

小机房的树 codevs 2370

2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要

UESTC_小panpan学图论 2015 UESTC Training for Graph Theory&lt;Problem J&gt;

J - 小panpan学图论 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 小panpan不会图论,所以图论专题他非常刻苦地学习图论. 今天他认真地学习了萌神的ppt,学习了一下Floyd算法,手持两把锟斤拷的他, 口中疾呼烫烫烫,马上找了到OJ上找了道FLoyd的题: n个点,m边的无向连通图,无重边,无自环,每条边的长度都是1,求任意两点之间的

花神游历各国 题解(小清新线段树/树状数组+并查集)

众所周知,这是一道小清新线段树 然而可以用树状数组水过去且跑得飞快 看到区间开方第一反应肯定是线段树懒标记区间修改之类的,但是这个东西似乎确凿不可维护 所以考虑暴力循环单点修改->T飞 于是我们关注一下开方本身的特殊性 我们知道,如果每次向下取整,一个数经过多次操作最终会变成1(或0) 事实上,大概经过 log(logx)次就会变成1 这是什么概念呢?经过博主测试,1e9只要经过五次开方取整就会变成1 那么接下来就能够利用1每次不必再操作优化复杂度 可以维护一个类似链表的结构,指向下一个>1的

小代学Spring Boot之数据源

想要获取更多文章可以访问我的博客?-?代码无止境. 经过一天对Spring Boot的研究,小代同学已经对Spring Boot框架有了一个大概的认识.并且还创建了一个简单的Spring Boot的Web应用程序,如果你还不知道如何创建的话,可以访问<小代学Spring Boot之开篇>这篇文章.下一步陈Boss让小代做的是使用Spring Boot项目连接数据库. 相信我们都知道,在连接数据库的时候我们一般都会使用数据库连接池,这样做的好处在于可以重用数据库资源,还可以统一管理数据库连接,避