[bfs序 线段树] HDU5957. Query on a graph

求出bfs序

那么一个点的儿子和孙子都是在bfs序上连续的一段

记一下这个区间,然后线段树维护一下

因为有环,那么肯定有多出来的一条边,给这条边的两个端点以及这两个端点连出去的点打个标记就好了

细节贼多

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

typedef long long ll;

const int N=100010;

int n,t,q,cnt,m,G[N];
struct edge{
  int t,nx;
}E[N<<1];

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &x){
  char c=nc(); x=0; int f=1;
  for(;c>'9'||c<'0';c=nc())if(c=='-')f=-f;for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc()); x*=f;
}

inline void addedge(int x,int y){
  E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt;
}

int fa[N],vis[N],sl[N],sr[N],gsl[N],gsr[N],Q[N],pos[N],d1[N],d2[N];
int l,r;

inline void bfs(){
  vis[1]=1; Q[l=r=1]=1; pos[1]=1;
  while(l<=r){
    int x=Q[l++];
    for(int i=G[x];i;i=E[i].nx)
      if(!vis[E[i].t]){
    Q[++r]=E[i].t; pos[E[i].t]=r; fa[E[i].t]=x; vis[E[i].t]=1;
      }
  }
  for(int k=r;k;k--){
    int x=Q[k]; sl[x]=gsl[x]=1<<30; sr[x]=gsr[x]=0;
    for(int i=G[x];i;i=E[i].nx)
      if(fa[E[i].t]==x){
    sl[x]=min(sl[x],pos[E[i].t]); sr[x]=pos[E[i].t];
    gsl[x]=min(gsl[x],sl[E[i].t]); gsr[x]=max(sr[E[i].t],gsr[x]);
      }
  }
  for(int i=1;i<=n;i++) d1[i]=d2[i]=0;
  for(int k=2;k<=cnt;k++){
    int x=E[k].t,y=E[k^1].t;
    if(fa[x]==y || fa[y]==x) continue;
    d1[x]=y; d1[y]=x;
    for(int i=G[x];i;i=E[i].nx)
      if(E[i].t!=y) d2[E[i].t]=y;
    for(int i=G[y];i;i=E[i].nx)
      if(E[i].t!=x) d2[E[i].t]=x;
  }
}

void PutAns(ll x){
  if(x>=10) PutAns(x/10); putchar(x%10+'0');
}

ll tag[N<<2],tot[N<<2],size[N<<2];

void Build(int g,int l,int r){
  tag[g]=tot[g]=0; size[g]=r-l+1;
  if(l==r) return ;
  int mid=l+r>>1;
  Build(g<<1,l,mid); Build(g<<1|1,mid+1,r);
}


inline void add(int g,ll x){
  tag[g]+=x; tot[g]+=size[g]*x;
}

inline void Push(int g){
  if(!tag[g]) return ;
  add(g<<1,tag[g]); add(g<<1|1,tag[g]); tag[g]=0;
}

inline void Up(int g){
  tot[g]=tot[g<<1]+tot[g<<1|1];
}

void Modify(int g,int l,int r,int L,int R,ll x){
  if(l>r) return;
  if(l==L && r==R) return add(g,x);
  int mid=L+R>>1; Push(g);
  if(r<=mid) Modify(g<<1,l,r,L,mid,x);
  else if(l>mid) Modify(g<<1|1,l,r,mid+1,R,x);
  else Modify(g<<1,l,mid,L,mid,x),Modify(g<<1|1,mid+1,r,mid+1,R,x);
  Up(g);
}

ll Query(int g,int l,int r,int L,int R){
  if(l>r) return 0;
  if(l==L && r==R) return tot[g];
  int mid=L+R>>1; Push(g);
  if(r<=mid) return Query(g<<1,l,r,L,mid);
  else if(l>mid) return Query(g<<1|1,l,r,mid+1,R);
  else return Query(g<<1,l,mid,L,mid)+Query(g<<1|1,mid+1,r,mid+1,R);
}

int main(){
  read(t);
  while(t--){
    read(n); cnt=1;
    for(int i=1;i<=n;i++)
      G[i]=vis[i]=fa[i]=0;
    for(int i=1,x,y;i<=n;i++)
      read(x),read(y),addedge(x,y);
    bfs(); Build(1,1,n);
    read(m);
    for(int i=1;i<=m;i++){
      char opt; while((opt=nc())!='M' && opt!='Q');
      if(opt=='M'){
    int x,k,d;
    read(x); read(k); read(d);
    if(k==0) Modify(1,pos[x],pos[x],1,n,d);
    else if(k==1){
      Modify(1,pos[x],pos[x],1,n,d);
      Modify(1,sl[x],sr[x],1,n,d);
      if(fa[x]) Modify(1,pos[fa[x]],pos[fa[x]],1,n,d);
      if(d1[x]) Modify(1,pos[d1[x]],pos[d1[x]],1,n,d);
    }
    else{
      if(fa[x]){
        Modify(1,pos[fa[x]],pos[fa[x]],1,n,d);
        Modify(1,sl[fa[x]],sr[fa[x]],1,n,d);
        if(fa[fa[x]]) Modify(1,pos[fa[fa[x]]],pos[fa[fa[x]]],1,n,d);
      }
      else Modify(1,pos[x],pos[x],1,n,d);
      Modify(1,sl[x],sr[x],1,n,d);
      Modify(1,gsl[x],gsr[x],1,n,d);
      if(d1[x]){
        int y=d1[x];
        if(fa[y] && fa[x]!=fa[y] && fa[y]!=fa[fa[x]] && fa[fa[y]]!=fa[x]) Modify(1,pos[fa[y]],pos[fa[y]],1,n,d);
        if(fa[y]!=fa[x]) Modify(1,pos[y],pos[y],1,n,d);
        Modify(1,sl[y],sr[y],1,n,d);
      }
      if(d2[x] && fa[d2[x]]!=fa[x] && fa[fa[d2[x]]]!=x && fa[d2[x]]!=x) Modify(1,pos[d2[x]],pos[d2[x]],1,n,d);
    }
      }
      else{
    ll ans=0; int x,k;
    read(x); read(k);
    if(k==0) ans=Query(1,pos[x],pos[x],1,n);
    else if(k==1){
      ans=Query(1,pos[x],pos[x],1,n)+Query(1,sl[x],sr[x],1,n);
      if(fa[x]) ans+=Query(1,pos[fa[x]],pos[fa[x]],1,n);
      if(d1[x]) ans+=Query(1,pos[d1[x]],pos[d1[x]],1,n);
    }
    else{
      if(fa[x]){
        ans=Query(1,pos[fa[x]],pos[fa[x]],1,n)+Query(1,sl[fa[x]],sr[fa[x]],1,n);
        if(fa[fa[x]]) ans+=Query(1,pos[fa[fa[x]]],pos[fa[fa[x]]],1,n);
      }
      else ans=Query(1,pos[x],pos[x],1,n);
      ans+=Query(1,sl[x],sr[x],1,n);
      ans+=Query(1,gsl[x],gsr[x],1,n);
      if(d1[x]){
        int y=d1[x];
        if(fa[y] && fa[y]!=fa[x] && fa[y]!=fa[fa[x]] && fa[fa[y]]!=fa[x]) ans+=Query(1,pos[fa[y]],pos[fa[y]],1,n);
        if(fa[y]!=fa[x]) ans+=Query(1,pos[y],pos[y],1,n);
        ans+=Query(1,sl[y],sr[y],1,n);
      }
      if(d2[x] && fa[d2[x]]!=fa[x] && fa[fa[d2[x]]]!=x && fa[d2[x]]!=x) ans+=Query(1,pos[d2[x]],pos[d2[x]],1,n);
    }
    if(ans<0) putchar('-'),ans=-ans;
    PutAns(ans); putchar('\n');
      }
      //for(int i=1;i<=n;i++) printf("%lld ",Query(1,pos[i],pos[i],1,n)); putchar('\n');
    }
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值