树链剖分 学习心得
Bug 都写在代码开头了,就不复述了。
还有一个智障的错误是注释调试代码的时候把同一行的正式代码也给注释掉了(
写得非常精彩。
/*
bug:1.rev、id要分清!
2.mod()函数的情况不能写一半就跑路!
3.别忘了先给tree build()一下!
4.出界条件认真想一遍再写!
5.还有出界的!
6.LazyTag pushdown()之后还需要重置!
Question:
1.有多少对长度为n 的rev 和id 是相同的?
*/
#include<bits/stdc++.h>
using namespace std;
#define N 100005
#define M 200005
#define ll long long
//#define DEBUG
#ifdef DEBUG
#define debugtive(x) int x
#define debug(x) {printf("%5s=",#x);cout<<(x)<<"\n";}
#define debugs(x,l,r){printf("%5s:",#x);for(int i=l;i<=r;++i){cout<<x[i]<<" ";}putchar('\n');}
#else
#define debugtive(x)
#define debug(x)
#define debugs(x,l,r)
#endif
ll n,m,R,P,val[N],ans;
int tot,first[N],nxt[M],to[M];
int top[N],rev[N],id[N],fah[N],siz[N],son[N],dfn,dep[N];
void add(int x,int y){
nxt[++tot]=first[x];
to[tot]=y;
first[x]=tot;
return;
}
void Add(ll &x,ll y){
x+=y;
if(x>=P)x-=P;
}
ll mod(ll x){
if(x>=P)return x-P;
return x; //bug #2
}
struct{
struct node{
int L,R;
node *l,*r;
ll sum,add;
debugtive(lev);
node(node *a=NULL,node *b=NULL,ll c=0,ll d=0){
l=a,r=b,sum=c,add=d;
}
void bu(){
if(l==NULL)l=new node();
if(r==NULL)r=new node();
}
void pushup(){
l->pushdown();
r->pushdown();
sum=mod(l->sum+r->sum);
}
void pushdown(){
if(add){
sum=(sum+(R-L+1)*add)%P;
if(l!=NULL)Add(l->add,add); //bug #5 l、r可能出界所以要判断
if(r!=NULL)Add(r->add,add); //bug #5 ↑
add=0; //bug #6 别忘了重置lazytag!
}
return;
}
#ifdef DEBUG
void out(bool andson){
for(int i=1;i<=lev;++i)putchar('\t');
printf("{[%d,%d]:sum=%lld add=%lld}\n",L,R,sum,add);
if(andson){
if(l!=NULL)l->out(1);
if(r!=NULL)r->out(1);
}
}
#endif
};
node* root;
void init(){
this->root=new node();
root->bu();
}
void build(node*x,int l,int r){
x->L=l,x->R=r;
if(l==r){
x->sum=val[id[l]]; //bug #1
return;
}
x->bu();
#ifdef DEBUG
x->l->lev=x->r->lev=x->lev+1;
#endif
int mid=(l+r)>>1;
build(x->l,l,mid);
build(x->r,mid+1,r);
x->pushup();
return;
}
ll query(node*x,int l,int r){
if(x->L>r||x->R<l)return 0; //bug #4
x->pushdown();
if(x->L>=l&&x->R<=r)return x->sum;
return mod(query(x->l,l,r)+query(x->r,l,r));
}
void update(node*x,int l,int r,ll val){
if(x->L>r||x->R<l)return; //bug #4
if(x->L>=l&&x->R<=r){
// printf("plate\n");
Add(x->add,val);
x->pushdown();
return;
}
x->pushdown(); //这里必须有,因为统计父节点sum的时候不会计算add,所以要把add给pushdown掉。
// printf("update[%d,%d]\n",l,r);x->out(1);
update(x->l,l,r,val);
update(x->r,l,r,val);
x->pushup();
return;
}
}tree;
void dfs1(int x){
siz[x]=1;
for(int e=first[x];e;e=nxt[e]){
int u=to[e];
if(siz[u])continue;
fah[u]=x;
dep[u]=dep[x]+1;
dfs1(u);
siz[x]+=siz[u];
if(siz[u]>siz[son[x]])son[x]=u;
}
}
void dfs2(int x,int curtop){
top[x]=curtop;
rev[x]=++dfn;
id[dfn]=x;
if(son[x])dfs2(son[x],curtop);
for(int e=first[x];e;e=nxt[e]){
int u=to[e];
if(top[u])continue;
if(u!=son[x]){
dfs2(u,u);
}
}
return;
}
int main(){
int x,y,z,opr;
scanf("%lld %lld %lld %lld",&n,&m,&R,&P);
for(int i=1;i<=n;++i){
scanf("%lld",&val[i]);
}
for(int i=1;i<n;++i){
scanf("%d %d",&x,&y);
add(x,y);
add(y,x);
}
top[R]=R;dep[R]=1;
dfs1(R);
dfs2(R,R);
tree.init();
#ifdef DEBUG
tree.root->lev=1;
debug(tree.root->lev);
#endif
tree.build(tree.root,1,n); //bug #3
// debugs(rev,1,n);
// debugs( id,1,n);
// debugs(top,1,n);
// debugs(dep,1,n);
// debugs(siz,1,n);
// debugs(val,1,n);
// tree.root->out(1);
for(int i=1;i<=m;++i){
scanf("%d",&opr);
switch(opr){
case 1:
scanf("%d %d %d",&x,&y,&z);
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
tree.update(tree.root,rev[top[x]],rev[x],z);
x=fah[top[x]];
}
if(rev[x]<rev[y])swap(x,y);
tree.update(tree.root,rev[y],rev[x],z);
// tree.root->out(1);
break;
case 2:
scanf("%d %d",&x,&y);
ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
Add(ans,tree.query(tree.root,rev[top[x]],rev[x]));
x=fah[top[x]];
}
if(rev[x]<rev[y])swap(x,y);
Add(ans,tree.query(tree.root,rev[y],rev[x]));
printf("%lld\n",ans%P);
break;
case 3:
scanf("%d %d",&x,&z);
debug(rev[x]);
debug(rev[x]+siz[x]-1);
tree.update(tree.root,rev[x],rev[x]+siz[x]-1,z);
// tree.root->out(1);
break;
default:
scanf("%d",&x);
printf("%lld\n",tree.query(tree.root,rev[x],rev[x]+siz[x]-1)%P);
break;
}
}
return 0;
}
//[Error]ld returned 1 exited status.