做题的时候头脑一定要清晰,我这种蒟蒻就不要妄想能在10min之内敲出这种代码了……当然,如果敲出来了,那么必定漏洞百出。
对于这题,直接对于给出的树的先序遍历序列建立线段树并维护即可。
但是!我用一个数组来存每个点的权值和S操作修改的权值。这个显然是错的,因为我没有考虑区间修改经过这个点的情况的贡献……然后就是不停的WA……捂脸.jpg
附上AC代码:
#include <cstdio>
#define lt (k<<1)
#define rt (k<<1|1)
#define mid (l+r>>1)
using namespace std;
typedef long long ll;
const int N=5e4+10;
struct side{
int to,nt;
}s[N];
int n,m,num,h[N],x;
int wz[N],sz[N],size;
ll t[N<<2],lz[N<<2],a[N],y,v;
char str[10];
inline void so(int x){
wz[x]=++size,sz[x]=1;
for (int i=h[x]; i; i=s[i].nt) so(s[i].to),sz[x]+=sz[s[i].to];
return;
}
inline void push(int k,int l,int r){
lz[lt]+=lz[k],t[lt]+=(mid-l+1)*lz[k];
lz[rt]+=lz[k],t[rt]+=(r-mid)*lz[k];
return (void)(lz[k]=0);
}
inline void change(int k,int l,int r,int ql,int qr,int v){
if (l>=ql&&r<=qr) return (void)(lz[k]+=v,t[k]+=1ll*(r-l+1)*v);
if (lz[k]) push(k,l,r);
if (ql<=mid) change(lt,l,mid,ql,qr,v);
if (qr>mid) change(rt,mid+1,r,ql,qr,v);
return (void)(t[k]=t[lt]+t[rt]);
}
inline ll query(int k,int l,int r,int ql,int qr){
if (l>=ql&&r<=qr) return t[k];
if (lz[k]) push(k,l,r);
ll ret=0;
if (ql<=mid) ret+=query(lt,l,mid,ql,qr);
if (qr>mid) ret+=query(rt,mid+1,r,ql,qr);
return ret;
}
int main(void){
scanf("%d%d",&n,&m);
for (int i=2; i<=n; ++i) scanf("%d%lld",&x,&a[i]),++x,s[++num]=(side){i,h[x]},h[x]=num;
so(1);
for (int i=1; i<=n; ++i) change(1,1,n,wz[i],wz[i],a[i]);
while (m--){
scanf("%s%d%lld%lld",str,&x,&y,&v),++x;
if (str[0]=='S'){
if (query(1,1,n,wz[x],wz[x])<y) change(1,1,n,wz[x],wz[x],v);
}
else {
ll tmp=query(1,1,n,wz[x],wz[x]+sz[x]-1);
if (tmp<1ll*y*sz[x]) change(1,1,n,wz[x],wz[x]+sz[x]-1,v);
}
}
for (int i=1; i<=n; ++i) printf("%lld\n",query(1,1,n,wz[i],wz[i]));
return 0;
}