版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/88252582
【题目】
Codechef
给定一棵
个点的有根树,每个节点都有一个权值,支持以下操作:
- 插入一个节点(作为树上一个节点的儿子)
- 删除一个子树
- 子树加
- 子树求和
,强制在线。
【解题思路】
这个动态加入叶子还要提出子树就很自闭。
不过稍加分析,我们在平时处理问题的时候,都是将子树信息通过 序转到序列上的。当然这题只用 序的话信息是不够的。我们可以采用括号序,每次新增一个点,相当于在序列上插入一对括号,查找子树时就是子树根节点对应的左右括号。
我们可以使用 来解决这个问题。
复杂度
【参考代码】
#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;
}