【平衡树维护括号序列】CC_ANUDTQ Dynamic Trees and Queries

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/88252582

【题目】
Codechef
给定一棵 n n 个点的有根树,每个节点都有一个权值,支持以下操作:

  • 插入一个节点(作为树上一个节点的儿子)
  • 删除一个子树
  • 子树加
  • 子树求和

n , Q 1 0 5 n,Q\leq 10^5 ,强制在线。

【解题思路】
这个动态加入叶子还要提出子树就很自闭。

不过稍加分析,我们在平时处理问题的时候,都是将子树信息通过 DFS \text{DFS} 序转到序列上的。当然这题只用 DFS \text{DFS} 序的话信息是不够的。我们可以采用括号序,每次新增一个点,相当于在序列上插入一对括号,查找子树时就是子树根节点对应的左右括号。

我们可以使用 s p l a y splay 来解决这个问题。

复杂度 O ( n + Q log n ) O(n+Q\log n)

【参考代码】

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=4e5+10;
int val[N],a[N];

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}
void write(ll x){if(x<0)putchar('-'),x=-x;if(x>9)write(x/10);putchar(x%10^48);}
void writeln(ll x){write(x);putchar('\n');}

struct Splay
{
#define ls (ch[x][0])
#define rs (ch[x][1])
	int sz,rt,fa[N],w[N],siz[N],tar[N],ch[N][2];
	ll sum[N];
	void pushup(int x){siz[x]=siz[ls]+siz[rs]+1;sum[x]=sum[ls]+sum[rs]+w[x];}	
	void up(int x,int c){w[x]+=c;sum[x]+=1ll*siz[x]*c;tar[x]+=c;}
	void pushdown(int x)
	{
		if(!tar[x]) return;
		if(ls) up(ls,tar[x]); if(rs) up(rs,tar[x]);
		tar[x]=0;
	}
	void newnode(int &x,int f,int c){x=++sz;fa[x]=f;w[x]=sum[x]=c;tar[x]=0;}
	void build(int &x,int f,int l,int r)
	{
		if(l>r) return;
		int mid=(l+r)>>1;x=a[mid];
		fa[x]=f;w[x]=sum[x]=val[(x+1)>>1];tar[x]=0;
		build(ls,x,l,mid-1);build(rs,x,mid+1,r);
		pushup(x);
	}
	int get(int x){return ch[fa[x]][1]==x;}
	void rotate(int x)
	{
		int y=fa[x],z=fa[y],k=get(x);
		pushdown(y);pushdown(x);
		if(z) ch[z][get(y)]=x;
		fa[ch[x][!k]]=y;fa[y]=x;fa[x]=z;
		ch[y][k]=ch[x][!k];ch[x][!k]=y;
		pushup(y);pushup(x);
	}
	void splay(int x,int goal)
	{
		while(fa[x]^goal)
		{
			int y=fa[x],z=fa[y];
			if(z^goal) rotate(get(y)==get(x)?y:x);
			rotate(x);
		}
		if(!goal) rt=x;
	}
	int getpre(int x){for(x=ls;rs;x=rs);return x;}
	int getsuc(int x){for(x=rs;ls;x=ls);return x;}
	void insert(int x,int c)
	{
		x=(x<<1)-1;splay(x,0);
		int y=getsuc(x);splay(y,x);
		newnode(ch[y][0],y,c);newnode(ch[ch[y][0]][1],ch[y][0],c);
		pushup(ch[ch[y][0]][1]);pushup(ch[y][0]);
		pushup(y);pushup(x);
	}
	void udpate(int x,int c)
	{
		x=(x<<1)-1;splay(x,0);splay(x+1,x);
		int y=ch[x+1][0];
		if(y) up(y,c);
		w[x]+=c;w[x+1]+=c;
		pushup(x+1);pushup(x);
	}
	void dele(int x)
	{
		x=(x<<1)-1;splay(x,0);splay(x+1,x);
		int l=getpre(x),r=getsuc(x+1);
		splay(l,0);splay(r,l);
		fa[ch[r][0]]=0;ch[r][0]=0;
		pushup(r);pushup(l);
	}
	ll query(int x)
	{
		x=(x<<1)-1;splay(x,0);splay(x+1,x);
		return (sum[ch[x+1][0]]>>1)+w[x];
	}
#undef ls
#undef rs
}T;

namespace DreamLolita
{
	int n,m,ind,tot;
	int head[N];
	ll ans;
	struct Tway{int v,nex;}e[N];
	void add(int u,int v)
	{
		e[++tot]=(Tway){v,head[u]};head[u]=tot;
		e[++tot]=(Tway){u,head[v]};head[v]=tot;
	}
	void dfs(int x,int f)
	{
		a[++ind]=(x<<1)-1;
		for(int i=head[x];i;i=e[i].nex) if(e[i].v^f) dfs(e[i].v,x);
		a[++ind]=(x<<1);
	}
	void solution()
	{
		n=read();
		for(int i=1;i<=n;++i) val[i]=read();
		for(int i=1;i<n;++i) add(read()+1,read()+1);
		dfs(1,0);T.build(T.rt,0,1,ind);T.sz=ind;
		m=read();
		while(m--)
		{
			int op=read(),v;int x=read()+ans+1;
			if(op==1) v=read(),T.insert(x,v);
			else if(op==2) v=read(),T.udpate(x,v);
			else if(op==3) T.dele(x);
			else writeln((ans=T.query(x)));
		}
	}
}

int main()
{
#ifdef Durant_Lee
	freopen("CC_ANUDTQ.in","r",stdin);
	freopen("CC_ANUDTQ.out","w",stdout);
#endif
	DreamLolita::solution();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/88252582