/*查找更新等操作 用新编号ne 变为有序的,再用线段树
ne[] 存的是dfs序编号 保证每个重链和子树都是编号连续的
有序区间才能用线段树 。所以l,r这些都是新编号,输入里的是旧编号*/
//找了半天读不全的错误
移位一定要加括号!!!!
i<<1|1=3
(i<<1)+1=3
i<<1+1=4
que的返回值是val 所以是ll
//mid和m别写混了。因为m一般定义为总量,所以以后中间都用mid!!!
//由于函数的参数比较多,调用函数的次数也比较多,所以参数的顺序尽量有规律
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e4+5;
int m,n,p,size[maxn],deep[maxn],f[maxn],son[maxn];
int cnt,head[maxn],nid[maxn],oid[maxn],ncnt,top[maxn];
ll a[maxn];
struct stree{
ll value,lazy;
}t[maxn<<2];//线段树范围是4倍
struct ss{int to,nex;}g[maxn<<1];//g是结构体 没法memset
void create(int u,int v){
g[++cnt]={v,head[u]}; head[u]=cnt;
}
//往下走 找重链和重儿子son[]
void dfs1(int x,int fath){
size[x]=1;deep[x]=deep[fath]+1;
son[x]=0;f[x]=fath;
for(int i=head[x];i;i=g[i].nex){
int v=g[i].to;
if(v==fath) continue;//不能往上走
dfs1(v,x);
size[x]+=size[v];//更新以x为根的树的大小
if(size[v]>size[son[x]]) son[x]=v;
}
}
void dfs2(int x,int topx){
top[x]=topx;//注意 topx不要定义成全局 递归调用时会乱
nid[x]=++ncnt;oid[ncnt]=x;
//因为neid初始化为0,要从1开始 所以++得在前
//有重儿子的话,先遍历重链,赋值nid,oid
if(son[x]) dfs2(son[x],topx);
//再遍历轻链
for(int i=head[x];i;i=g[i].nex){
int v=g[i].to;
if(v!=f[x]&&v!=son[x]){
dfs2(v,v);
}
}
}
void build(int l=1,int r=n,int rt=1){//建线段树
t[rt].lazy=0;
//建树时给每个点lazy赋初值,所以lazy在外面 。若在l==r时执行 只有叶节点
if(l==r){
t[rt].value=a[oid[l]];//因为a[]下标存的是旧id
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1); build(mid+1,r,rt<<1|1);
t[rt].value=t[rt<<1].value+t[rt<<1|1].value;
//构造都要pushup
}
//lazy value更新都是 加上(减去)用+= 。变为 用=
void pushdown(int ln,int rn,int rt){
if(t[rt].lazy){
t[rt<<1].value+=t[rt].lazy*ln;
t[rt<<1|1].value+=t[rt].lazy*rn;
t[rt<<1].lazy+=t[rt].lazy;
t[rt<<1|1].lazy+=t[rt].lazy;
}
t[rt].lazy=0;
}
void update(ll k,int L,int R,int l=1,int r=n,int rt=1){
if(L>r||R<l) return ;
if(L<=l&&r<=R){
t[rt].value+=k*(r-l+1);
t[rt].lazy+=k;
return ;
}
int mid=(l+r)>>1;
pushdown(mid-l+1,r-mid,rt);
update(k,L,R,l,mid,rt<<1);
update(k,L,R,mid+1,r,rt<<1|1);
//该题是单点查询,所以不用pushup求和
}
ll que(int k,int l=1,int r=n,int rt=1){
if(k<l||k>r) return 0;
//超出范围回0,所以后面可以直接返回左右相加
if(l==r) return t[rt].value;
int mid=(l+r)>>1;
pushdown(mid-l+1,r-mid,rt);
//有lazy所以mid后面都要pushdown 才能保证value是正确的
return que(k,l,mid,rt<<1)+que(k,mid+1,r,rt<<1|1);
}
void change(int x,int y,ll k){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]]) swap(x,y);
update(k,nid[top[x]],nid[x]);
//更新深度大的那条链,更新完了再向上跳
//topx和x是旧编码,要用线段树得用新编码,所以得用nid
x=f[top[x]];
}
//前面是while所以一直跳到top相等 即xy在同一重链上(dfs序连续可转为线段树)再更新x到y区间
if(deep[x]>deep[y]) swap(x,y);;
update(k,nid[x],nid[y]);
}
//change:找到最近公共祖先 并分段update
int main(){
int x,y;ll k;
while(~scanf("%d%d%d",&n,&m,&p)){
cnt=ncnt=0;
for(int i=1;i<=n;i++){
head[i]=0;
scanf("%lld",&a[i]);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
create(x,y);
create(y,x);
}
dfs1(1,0);dfs2(1,1);
build();
for(int i=1;i<=p;i++){
char ch[10];
scanf("%s",ch);//%s遇空格结束
if(ch[0]=='Q') {
scanf("%d",&x);
printf("%lld\n",que(nid[x]));
}
else{
scanf("%d%d%lld",&x,&y,&k);
if(ch[0]=='I') change(x,y,k);
else change(x,y,-k);
}
}
}
return 0;
}