题目链接:https://vjudge.net/contest/279350#problem/A
题目大意:n个点,m条边,然后q次询问,因为在树上,两个点能确定一条直线,我们可以对这条直线上的所有值进行加减操作,也可以单点询问。
各个数组的作用:sto是刚开始的输入数据,head是前向星,dfsnum指的是dfs序,depth指的是每个点的深度son指的是每个节点的重儿子,father指的是每个点的父节点,Size指的是以当前点为根节点的树,ord指的是遍历顺序,cost指的是编号之后的每个点,top指的是当前的这条重链的最顶端的那个点,剩下的就是线段树的数组了。
注意点:我们通过两个dfs来给这些数组赋值,通过第一个dfs,我们可以把depth和father,size,son求出来,剩下的ord和top通过第二个dfs求出来,为什么使用两个dfs?我的理解就是,第一个dfs和第二个dfs的遍历条件并不相同,第一个dfs就是能走就走,第二个dfs是在按照已经分好链的前提下进行走的,也就是说这里的ord数组并不能在第一个dfs中实现,只能在第二个数组中实现。(后续有新的理解会继续补充)。
AC代码:
1 #include<iostream> 2 #include<cmath> 3 #include<stack> 4 #include<queue> 5 #include<stdio.h> 6 #include<string> 7 #include<cstring> 8 #include<algorithm> 9 using namespace std; 10 # define inf 0x3f3f3f3f 11 # define ll long long 12 # define lson l,m,rt<<1 13 # define rson m+1,r,rt<<1|1 14 const int maxn = 5e4+100; 15 int sto[maxn],head[maxn],edgnum,dfsnum,depth[maxn]; 16 int son[maxn],father[maxn],Size[maxn],ord[maxn],cost[maxn],top[maxn]; 17 int tree[maxn<<2],lazy[maxn<<2]; 18 struct node 19 { 20 int to; 21 int nex; 22 } edge[maxn<<2]; 23 void addedge(int fr,int to) 24 { 25 edge[edgnum].nex=head[fr]; 26 edge[edgnum].to=to; 27 head[fr]=edgnum++; 28 } 29 void dfs1(int fr,int rt,int dep) 30 { 31 father[fr]=rt; 32 Size[fr]=1; 33 son[fr]=-1; 34 depth[fr]=dep; 35 for(int i=head[fr]; i!=-1; i=edge[i].nex) 36 { 37 int to=edge[i].to; 38 if(to==rt) 39 continue; 40 dfs1(to,fr,dep+1); 41 Size[fr]+=Size[to]; 42 if(son[to]==-1||(Size[son[fr]]<Size[to])) 43 { 44 son[fr]=to; 45 } 46 } 47 } 48 void dfs2(int fr,int rt) 49 { 50 ord[fr]=++dfsnum; 51 cost[ord[fr]]=sto[fr]; 52 top[fr]=rt; 53 if(son[fr]!=-1) 54 dfs2(son[fr],rt); 55 for(int i=head[fr]; i!=-1; i=edge[i].nex) 56 { 57 int u=edge[i].to; 58 if(son[fr]!=u&&father[fr]!=u) 59 { 60 dfs2(u,u); 61 } 62 } 63 } 64 void init() 65 { 66 dfsnum=0; 67 dfs1(1,-1,1); 68 dfs2(1,1); 69 } 70 void up(int rt) 71 { 72 tree[rt]=tree[rt<<1]+tree[rt<<1|1]; 73 } 74 void down(int len,int rt) 75 { 76 if(lazy[rt]) 77 { 78 lazy[rt<<1]+=lazy[rt]; 79 lazy[rt<<1|1]+=lazy[rt]; 80 tree[rt<<1]+=(len-len/2)*lazy[rt]; 81 tree[rt<<1|1]+=(len/2)*lazy[rt]; 82 lazy[rt]=0; 83 } 84 } 85 void buildtree(int l,int r,int rt) 86 { 87 lazy[rt]=0; 88 tree[rt]=0; 89 if(l==r) 90 { 91 tree[rt]=cost[l]; 92 return ; 93 } 94 int m=(l+r)>>1; 95 buildtree(lson); 96 buildtree(rson); 97 up(rt); 98 } 99 void update(int l,int r,int rt,int L,int R,int p) 100 { 101 if(L<=l&&R>=r) 102 { 103 tree[rt]+=p*(r-l+1); 104 lazy[rt]+=p; 105 return ; 106 } 107 down(r-l+1,rt); 108 int m=(l+r)>>1; 109 if(L<=m) 110 update(lson,L,R,p); 111 if(R>m) 112 update(rson,L,R,p); 113 up(rt); 114 } 115 void Update(int n,int x,int y,int p) 116 { 117 int tx=top[x],ty=top[y]; 118 while(tx!=ty) 119 { 120 if(depth[tx]<depth[ty]) 121 { 122 swap(tx,ty); 123 swap(x,y); 124 } 125 update(1,n,1,ord[tx],ord[x],p); 126 x=father[tx],tx=top[x]; 127 } 128 if(depth[x]<depth[y]) 129 { 130 swap(x,y); 131 } 132 update(1,n,1,ord[y],ord[x],p); 133 } 134 int query(int l,int r,int rt,int pos) 135 { 136 if(l==r) 137 { 138 return tree[rt]; 139 } 140 down(r-l+1,rt); 141 int ans=0; 142 int m=(l+r)>>1; 143 if(pos<=m) 144 ans+=query(lson,pos); 145 if(pos>m) 146 ans+=query(rson,pos); 147 return ans; 148 up(rt); 149 } 150 int main() 151 { 152 int n,m,q; 153 while(~scanf("%d %d %d",&n,&m,&q)) 154 { 155 edgnum=0; 156 for(int i=1; i<=n; i++) 157 { 158 scanf("%d",&sto[i]); 159 head[i]=-1; 160 } 161 int t1,t2; 162 for(int i=1; i<=m; i++) 163 { 164 scanf("%d %d",&t1,&t2); 165 addedge(t1,t2); 166 addedge(t2,t1); 167 } 168 init(); 169 char str[10]; 170 buildtree(1,n,1); 171 int t3; 172 while(q--) 173 { 174 scanf("%s",str); 175 if(str[0]=='I') 176 { 177 scanf("%d %d %d",&t1,&t2,&t3); 178 Update(n,t1,t2,t3); 179 } 180 else if(str[0]=='Q') 181 { 182 scanf("%d",&t1); 183 int ans=query(1,n,1,ord[t1]); 184 printf("%d ",ans); 185 } 186 else if(str[0]=='D') 187 { 188 scanf("%d %d %d",&t1,&t2,&t3); 189 Update(n,t1,t2,-t3); 190 } 191 } 192 } 193 return 0; 194 }