Jiu Yuan Wants to Eat
題意:unsigned long long 型的數,四種操作:操作1樹上區間乘以某個數,操作2樹上區間加上某個數,操作3樹上區間反轉,即二進制1變成0,0變成1,操作四求和,由於是unsigned long long,所以變量自動取模。
注意點:線段樹多重標記,主要是乘法的lazy標記最好爲1,因爲在別的題可能爲0爲1無所謂只要處理好就行,但是這個題只能爲1,因爲如果爲0那麼lazy標記有可能經過一些操作取模後變成0,這時候其實區間應該全乘以0,但是實際導致區間不變,即lazy標記無效,所以乘法的lazy標記設爲1纔是最合理的。
#include<iostream>
#include<cstdio>
using namespace std;
typedef unsigned long long ull;
const int MAX_N=100100;
int size[MAX_N],wson[MAX_N],dfn[MAX_N],deep[MAX_N],pre[MAX_N],top[MAX_N],fa[MAX_N];
int head[MAX_N],Next[2*MAX_N],ver[2*MAX_N];
int tot,cnt;
struct node{
int l,r;
ull sum,lazy1,lazy2;
}a[MAX_N*4];
void update(int k){
a[k].sum=a[k<<1].sum+a[k<<1|1].sum;
}
void build(int k,int l,int r){
a[k].l=l;a[k].r=r;a[k].lazy1=1;a[k].lazy2=0;
if(l==r){
a[k].sum=0;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
update(k);
}
void pushdown(int k){
if(a[k].lazy1==1&&a[k].lazy2==0)
return;
a[k<<1].sum*=a[k].lazy1;
a[k<<1].lazy1*=a[k].lazy1;
a[k<<1].lazy2*=a[k].lazy1;
a[k<<1|1].sum*=a[k].lazy1;
a[k<<1|1].lazy1*=a[k].lazy1;
a[k<<1|1].lazy2*=a[k].lazy1;
a[k<<1].sum+=(ull)(a[k<<1].r-a[k<<1].l+1)*a[k].lazy2;
a[k<<1].lazy2+=a[k].lazy2;
a[k<<1|1].sum+=(ull)(a[k<<1|1].r-a[k<<1|1].l+1)*a[k].lazy2;
a[k<<1|1].lazy2+=a[k].lazy2;
a[k].lazy1=1;a[k].lazy2=0;
}
void changeS_1(int k,int l,int r,ull y){
if(a[k].l>=l&&a[k].r<=r){
a[k].sum*=y;
a[k].lazy1*=y;
a[k].lazy2*=y;
return;
}
pushdown(k);
int mid=(a[k].l+a[k].r)>>1;
if(l<=mid)
changeS_1(k<<1,l,r,y);
if(r>mid)
changeS_1(k<<1|1,l,r,y);
update(k);
}
void changeS_2(int k,int l,int r,ull y){
if(a[k].l>=l&&a[k].r<=r){
a[k].sum+=(ull)(a[k].r-a[k].l+1)*y;
a[k].lazy2+=y;
return;
}
pushdown(k);
int mid=(a[k].l+a[k].r)>>1;
if(l<=mid)
changeS_2(k<<1,l,r,y);
if(r>mid)
changeS_2(k<<1|1,l,r,y);
update(k);
}
ull query(int k,int l,int r){
if(a[k].l>=l&&a[k].r<=r)
return a[k].sum;
pushdown(k);
int mid=(a[k].l+a[k].r)>>1;
ull x=0;
if(l<=mid)
x+=query(k<<1,l,r);
if(r>mid)
x+=query(k<<1|1,l,r);
return x;
}
void Add(int x,int y){
ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
}
void dfs1(int x,int fat){
size[x]=1;
for(int i=head[x];i;i=Next[i]){
int y=ver[i];
if(y==fat)
continue;
deep[y]=deep[x]+1;
fa[y]=x;
dfs1(y,x);
size[x]+=size[y];
if(size[wson[x]]<size[y])
wson[x]=y;
}
}
void dfs2(int x,int tp){
dfn[x]=++cnt;
pre[cnt]=x;
top[x]=tp;
if(wson[x])
dfs2(wson[x],tp);
for(int i=head[x];i;i=Next[i]){
int y=ver[i];
if(y!=wson[x]&&y!=fa[x])
dfs2(y,y);
}
}
void modify_1(int x,int y,ull d){//修改x到y路徑上的值
while(top[x]!=top[y]){
if(dfn[top[x]]<dfn[top[y]])
swap(x,y);
//cout<<top[x]<<" "<<x<<" !\n";
//cout<<dfn[top[x]]<<" "<<" "<<dfn[x]<<" ?\n";
changeS_1(1,dfn[top[x]],dfn[x],d);
x=fa[top[x]];
}
if(deep[x]>deep[y])
swap(x,y);
//cout<<dfn[x]<<" "<<dfn[y]<<" ?\n";
//cout<<x<<" "<<y<<" !\n";
changeS_1(1,dfn[x],dfn[y],d);
}
void modify_2(int x,int y,ull d){//修改x到y路徑上的值
while(top[x]!=top[y]){
if(dfn[top[x]]<dfn[top[y]])
swap(x,y);
changeS_2(1,dfn[top[x]],dfn[x],d);
x=fa[top[x]];
}
if(deep[x]>deep[y])
swap(x,y);
changeS_2(1,dfn[x],dfn[y],d);
}
ull Qsum(int x,int y){
ull ret=0;
while(top[x]!=top[y]){
if(dfn[top[x]]<dfn[top[y]])
swap(x,y);
ret+=query(1,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if(deep[x]>deep[y])
swap(x,y);
ret+=query(1,dfn[x],dfn[y]);
return ret;
}
int main(void){
int i,n,m,q,x,y,op,z;
while(scanf("%d",&n)!=EOF){
for(i=1;i<=n;i++){
head[i]=0;
deep[i]=0;
wson[i]=0;
}
tot=0;
cnt=0;
for(i=2;i<=n;i++){
scanf("%d",&x);
Add(x,i);
Add(i,x);
}
deep[1]=1;
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
scanf("%d",&q);
for(i=0;i<q;i++){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&x,&y,&z);
modify_1(x,y,z);
}
else if(op==2){
scanf("%d%d%d",&x,&y,&z);
modify_2(x,y,z);
}
else if(op==3){
scanf("%d%d",&x,&y);
modify_1(x,y,-1);
modify_2(x,y,-1);
}
else if(op==4){
scanf("%d%d",&x,&y);
printf("%llu\n",Qsum(x,y));
}
}
}
return 0;
}