如果这道题没有一个限制,那么就是一道树状数组+dfs序的裸题
第一个请求或许会带来困惑,导致想要动态建树,如果真的动态修改树,那么dfs序必定会改变,很难维护,并且数据很大,暴力应该会T
所以不妨先把全部的节点建好,这样只需要求一次dfs序,而对于第一种操作
我们只需要再那个位置减去在他之前的dfs序的bouns求和,并在这个的后一个位置+回来,这样就有这个点被修改,并且成为了一个新点,等同于要求的操作
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<string> #include<cstring> #include<map> #include<set> using namespace std; typedef long long ll; const int N=1e6+10; const int inf=0x3f3f3f3f; ll tr[N]; ll mul[N]; ll bouns[N]; int idx; int times; int h[N],e[N],ne[N],cnt=1; struct node{ int type; int id; int v; }q[N]; struct q{ int st; int ed; }pos[N]; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void dfs(int u){ pos[u].st=++times; int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; dfs(j); } pos[u].ed=times; } int lowbit(int x){ return x&-x; } void add1(int x,ll c){ int i; for(i=x;i<=cnt;i+=lowbit(i)){ tr[i]+=c; } } ll sum(int x){ int i; ll res=0; for(i=x;i;i-=lowbit(i)){ res+=tr[i]; } return res; } int main(){ int i; int m,s; cin>>m>>s; memset(h,-1,sizeof h); for(i=1;i<=m;i++){ scanf("%d",&q[i].type); scanf("%d",&q[i].id); if(q[i].type==1){ cnt++; add(q[i].id,cnt); q[i].v=cnt; } else if(q[i].type==2||q[i].type==3){ scanf("%d",&q[i].v); } } for(i=1;i<=cnt;i++) mul[i]=s; dfs(1); for(i=1;i<=m;i++){ if(q[i].type==1){ ll tmp=sum(pos[q[i].v].st); add1(pos[q[i].v].st,-tmp); add1(pos[q[i].v].st+1,tmp); } else if(q[i].type==2){ ll tmp=sum(pos[q[i].id].st); bouns[q[i].id]+=tmp*mul[q[i].id]; mul[q[i].id]=(ll)q[i].v; add1(pos[q[i].id].st,-tmp); add1(pos[q[i].id].st+1,tmp); } else if(q[i].type==3){ int place1=pos[q[i].id].st; int place2=pos[q[i].id].ed; add1(place1,q[i].v); add1(place2+1,-q[i].v); } else{ printf("%lld\n",bouns[q[i].id]+sum(pos[q[i].id].st)*mul[q[i].id]); } } }
原文地址:https://www.cnblogs.com/ctyakwf/p/12571191.html
时间: 2024-10-08 20:34:26