BZOJ4034 树上操作
题目链接:https://vjudge.net/problem/HYSBZ-4034
知识点: 欧拉序列、线段树
解题思路:
先用 $DFS$ 预处理出树的欧拉序列。对于每一个点,如果它是第一次遍历到的,那么就置其 $flag[] = +1$;如果是在回溯时遍历到的,则置其 $flag[] = -1$。如此一来,当执行操作$3$,“询问某个节点 $x$ 到根的路径中所有点的点权和”时,只需查询欧拉序列中 $x$ 首次出现的序号及其之前是所有的点权乘上其相应的 flag 即为答案。
对于操作$1$,直接将 $x$ 的两个欧拉序列号 $id[x][0], id[x][1]$ 所对应的点加上 $a$ 乘相应的 $flag$ 的值即可;
对于操作$2$,则将 $[ id[x][0], id[x][1] ]$ 中的所有点加上 $a$ 乘相应的 $flag$ 的值;
具体操作请看代码,代码中利用一个 $tag[]$ 来记录区间中所有 $flag[]$ 的和,方便区间加操作;$tree[]$ 记录的是区间和。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 typedef long long LL; 6 const int MAXN=100000+5; 7 8 vector<int> G[MAXN]; 9 int pos[MAXN<<1],cnt; 10 int id[MAXN][2]; 11 LL val[MAXN],flag[MAXN<<1]; 12 LL tree[MAXN<<3],tag[MAXN<<3],lazy[MAXN<<3]; 13 14 void dfs(int rt,int last){ 15 cnt++; 16 pos[cnt]=rt,flag[cnt]=1; 17 if(!id[rt][0]) id[rt][0]=cnt; 18 for(int i=0;i<G[rt].size();i++){ 19 int v=G[rt][i]; 20 if(v!=last) 21 dfs(v,rt); 22 } 23 cnt++; 24 pos[cnt]=rt,flag[cnt]=-1; 25 id[rt][1]=cnt; 26 } 27 void pushup(int rt){ 28 tree[rt]=tree[rt<<1]+tree[rt<<1|1]; 29 } 30 void pushdown(int rt){ 31 tree[rt<<1]+=lazy[rt]*tag[rt<<1]; 32 tree[rt<<1|1]+=lazy[rt]*tag[rt<<1|1]; 33 lazy[rt<<1]+=lazy[rt],lazy[rt<<1|1]+=lazy[rt]; 34 lazy[rt]=0; 35 } 36 void build(int l,int r,int rt){ 37 if(l==r){ 38 tree[rt]=flag[l]*val[pos[l]]; 39 tag[rt]=flag[l]; 40 return; 41 } 42 int m=(l+r)/2; 43 build(lson); build(rson); 44 tag[rt]=tag[rt<<1]+tag[rt<<1|1]; 45 pushup(rt); 46 } 47 void update(int L,int R,LL val,int l,int r,int rt){ 48 if(L<=l&&r<=R){ 49 lazy[rt]+=val; 50 tree[rt]+=tag[rt]*val; 51 return; 52 } 53 if(lazy[rt]) pushdown(rt); 54 int m=(l+r)/2; 55 if(L<=m) update(L,R,val,lson); 56 if(R>m) update(L,R,val,rson); 57 pushup(rt); 58 } 59 LL query(int L,int R,int l,int r,int rt){ 60 if(L<=l&&r<=R) return tree[rt]; 61 if(lazy[rt]) pushdown(rt); 62 int m=(l+r)/2; 63 LL ret=0; 64 if(L<=m) ret+=query(L,R,lson); 65 if(m<R) ret+=query(L,R,rson); 66 return ret; 67 } 68 69 int main(){ 70 // freopen("in.txt","r",stdin); 71 int n,m; 72 scanf("%d%d",&n,&m); 73 for(int i=1;i<=n;i++) scanf("%lld",&val[i]); 74 for(int i=1;i<n;i++){ 75 int u,v; 76 scanf("%d%d",&u,&v); 77 G[u].push_back(v); 78 G[v].push_back(u); 79 } 80 cnt=0; 81 dfs(1,-1); 82 build(1,cnt,1); 83 84 while(m--){ 85 int od,x; 86 LL a; 87 scanf("%d",&od); 88 if(od==1){ 89 scanf("%d%lld",&x,&a); 90 update(id[x][0],id[x][0],a,1,cnt,1); 91 update(id[x][1],id[x][1],a,1,cnt,1); 92 } 93 else if(od==2){ 94 scanf("%d%lld",&x,&a); 95 update(id[x][0],id[x][1],a,1,cnt,1); 96 } 97 else{ 98 scanf("%d",&x); 99 printf("%lld\n",query(1,id[x][0],1,cnt,1)); 100 } 101 } 102 return 0; 103 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”