开始可以过样例,然而交一直WA。肉眼差错=0,拿小数据写暴力对拍果然拍出错了,改!大数据!拍!没错了。交!WA。。。又把题面看了几遍,瞄到一个绝对值什么的嗤笑一声逗我树节点的权值怎么会是负的。于是半小时后突然想到为什么不能是负的。。。就A了。。。细节细节不要太多理所当然。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define rep(i,n) for(int i=1;i<=n;i++)
#define clr(x,c) memset(x,c,sizeof(x))
#define qwq(x) for(edge *o=head[x];o;o=o->next)
#define op() clr(head,0);pt=edges;
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
#define adde(u,v) add(u,v),add(v,u)
#define ll long long
int read(){
int x=0;char c=getchar();bool f=true;
while(!isdigit(c)) {
if(c=='-') f=false; c=getchar();
}
while (isdigit(c)) x=x*10+c-'0',c=getchar();
return f?x:-x;
}
const int nmax=100005;
const int inf=0x7f7f7f7f;
struct edge{
int to;edge *next;
};
edge edges[nmax<<1],*pt,*head[nmax];
int son[nmax],size[nmax],dep[nmax],id[nmax],idx[nmax<<2],tp[nmax],fa[nmax],w[nmax],lft[nmax],rht[nmax],n;
ll sum[nmax<<2],col[nmax<<2];
void add(int u,int v){
pt->to=v;pt->next=head[u];head[u]=pt++;
}
void dfs(int x,int father){
size[x]=1;
qwq(x){
int to=o->to;
if(to==father) continue;
dep[to]=dep[x]+1;fa[to]=x;dfs(to,x);
size[x]+=size[to];
if(!son[x]||size[to]>size[son[x]]) son[x]=to;
}
}
void Dfs(int x,int top){
id[x]=++id[0];idx[id[0]]=x;lft[x]=id[0];tp[x]=top;
if(son[x]) Dfs(son[x],top);
qwq(x) if(!id[o->to]) Dfs(o->to,o->to);
rht[x]=id[0];
}
void build(int l,int r,int x){
if(l==r) {
sum[x]=w[idx[l]];return ;
}
int m=(l+r)>>1;build(lson);build(rson);sum[x]=sum[x<<1]+sum[x<<1|1];
}
void pushdown(int x,int tmp){
if(col[x]){
sum[x<<1]+=col[x]*(tmp-(tmp>>1));sum[x<<1|1]+=col[x]*(tmp>>1);
col[x<<1]+=col[x];col[x<<1|1]+=col[x];col[x]=0;
}
}
void update(int tl,int tr,int add,int l,int r,int x){
if(tl<=l&&tr>=r){
sum[x]+=(ll)add*(r-l+1);col[x]+=add;return ;
}
pushdown(x,r-l+1);
int m=(l+r)>>1;
if(tl<=m) update(tl,tr,add,lson);
if(tr>m) update(tl,tr,add,rson);
sum[x]=sum[x<<1]+sum[x<<1|1];
}
ll query(int tl,int tr,int l,int r,int x){
if(tl<=l&&tr>=r) return sum[x];
pushdown(x,r-l+1);
int m=(l+r)>>1;ll ans=0;
if(tl<=m) ans+=query(tl,tr,lson);
if(tr>m) ans+=query(tl,tr,rson);
return ans;
}
ll qsum(int a,int b){
ll ans=0;
while(tp[a]!=tp[b]) {
ans+=query(id[tp[b]],id[b],1,n,1);
b=fa[tp[b]];
//printf("%d ",tp[b]);
}
//printf("\n");
ans+=query(id[a],id[b],1,n,1);
return ans;
}
int main(){
/*freopen("data.out","r",stdin);
freopen("4034.out","w",stdout);*/
op();
n=read();int m=read(),u,v,d;
rep(i,n) w[i]=read();
rep(i,n-1) u=read(),v=read(),adde(u,v);
clr(fa,0);clr(son,0);dep[1]=0;
clr(id,0);
dfs(1,-1);
//rep(i,n) printf("%d:%d %d %d %d\n",i,fa[i],size[i],son[i],dep[i]);
Dfs(1,1);
//rep(i,n) printf("%d ",id[i]);printf("\n");
//rep(i,n) printf("%d ",tp[i]);
build(1,n,1);
rep(i,m){
u=read();
if(u==1) v=read(),d=read(),update(id[v],id[v],d,1,n,1);
else if(u==2) v=read(),d=read(),update(lft[v],rht[v],d,1,n,1);
else v=read(),printf("%lld\n",qsum(1,v));
}
return 0;
}
4034: [HAOI2015]T2
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2654 Solved: 835
[Submit][Status][Discuss]
Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input
第一行包含两个整数 N, M 。表示点数和操作数。
接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。
再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操
作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
Sample Output
6
9
13
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不
会超过 10^6 。