Jiu Yuan Wants to Eat 树链剖分和线段树多重标记

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值