BZOJ3589: 动态树

树链剖分。。
沃日打错树剖+路径并
感觉要滚粗啊

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
#define ll long long
const
  ll Mod=1ll<<31;
char c;
inline void read(ll &a)
{
    a=0;do c=getchar();while(c<'0'||c>'9');
    while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}

struct Chain
{
    Chain *next;
    ll u;
}*Head[300001];
#define ll long long
ll Dep[300001];

namespace LC
{
ll Len[600001];
ll ST[1000001][20];
ll In[600001];
ll Block[600001];
ll tot;
inline ll L(ll x,ll y){return Dep[x]<Dep[y]?x:y;}
inline ll LCA(ll a,ll b)
{
    if(!(a^b))return a;
    ll x=In[a],y=In[b];
    if(x>y)swap(x,y);
    ll Len=y-x+1,Bl=Block[Len];
    return L(ST[x][Bl],ST[y-(1<<Bl)+1][Bl]);
}

ll Dis(ll u,ll v){return Len[u]+Len[v]-2*Len[LCA(u,v)];}
inline void Bg()
{
    Len[0]=1ll<<29;
    Dep[0]=1ll<<29;
    ll base;
      for(ll i=1,base=1;i<=19;i++,base<<=1)
         for(ll j=1;j<=tot;j++)
             ST[j][i]=L(ST[j][i-1],ST[j+base][i-1]);
    ll con=0;
    for(ll i=1;i<=tot;i++)
      if(i^(i&-i))Block[i]=con-1;
      else Block[i]=con++;
}

void DFS(ll u,ll fa,ll dep)
{
    Dep[u]=dep;
    ST[In[u]=++tot][0]=u;
    for(Chain*tp=Head[u];tp;tp=tp->next)
      if(tp->u^fa)
       {
         DFS(tp->u,u,dep+1);
         ST[++tot][0]=u;
       } 
    if(u^fa)return ;
    Bg();
}
}
ll t;
namespace Seg
{
  struct N
  {
    ll l,r;
    ll sum,flag;
  }T[600001];
  inline void Build(ll place,ll l,ll r)
  {
    ll Mid=l+r>>1,lc=place<<1,rc=lc|1;
    T[place].l=l,T[place].r=r;
    if(l^r)
      Build(lc,l,Mid),Build(rc,Mid+1,r);
  }
  inline void AddFlag(ll place,ll Delta)
  {
    T[place].flag+=Delta,T[place].sum+=Delta*(T[place].r-T[place].l+1);
    T[place].flag%=Mod,T[place].sum%=Mod;
  }
  inline void pushdown(ll place)
  {
    ll lc=place<<1,rc=lc|1;
    T[lc].flag+=T[place].flag,T[rc].flag+=T[place].flag;
    T[lc].sum+=T[place].flag*(T[lc].r-T[lc].l+1),
    T[rc].sum+=T[place].flag*(T[rc].r-T[rc].l+1);
    T[lc].flag%=Mod;T[rc].flag%=Mod;
    T[lc].sum%=Mod;T[rc].sum%=Mod;
    T[place].flag=0;
   }
  void Add(ll place,ll l,ll r,ll Delta)
  {
    if(T[place].l>=l&&T[place].r<=r)
      { AddFlag(place,Delta);return;}
//      if(T[place].flag)pushdown(place);
    ll lc=place<<1,rc=lc|1,Mid=T[lc].r;
    if(Mid<r)Add(rc,l,r,Delta);
    if(Mid>=l)Add(lc,l,r,Delta);
    T[place].sum=(T[lc].sum+T[rc].sum+T[place].flag*(T[place].r-T[place].l+1))%Mod;
  }
  ll Query(ll place,ll l,ll r)
  {
    if(T[place].l>=l&&T[place].r<=r)return T[place].sum;
//    if(T[place].flag)pushdown(place);
    ll res=T[place].flag*(min(r,T[place].r)-max(l,T[place].l)+1),lc=place<<1,rc=lc|1,Mid=T[lc].r;
     if(l<=Mid)res+=Query(lc,l,r);
     if(r>Mid)res+=Query(rc,l,r);
    res%=Mod;
    return res;
  }
}
struct Path{ll f,s;};

Path operator &(Path a,Path b)
{
    Path res;
    res.f=LC::LCA(a.f,b.f);
    if(res.f==b.f)res.f=a.f;
    else if(res.f==a.f)res.f=b.f;
    else return (Path){-1,-1};
    res.s=LC::LCA(a.s,b.s);
    if(Dep[res.f]>Dep[res.s])return (Path){-1,-1};
    return res;
}
ll K;
Path X[30001];
ll HeavySon[300001],Size[300001],F[300001];
void DFS(ll u,ll f)
{
    Size[u]++;
    F[u]=f;
    for(Chain *tp=Head[u];tp;tp=tp->next)
      if(tp->u!=f)
        {
            DFS(tp->u,u);
            Size[u]+=Size[tp->u];
            if(Size[tp->u]>Size[HeavySon[u]])HeavySon[u]=tp->u;
        }
}

ll tot,CBG[300001],CED[300001],CPL[300001],CND[300001];
void DFS2(ll u,ll f,ll BG)
{
    CBG[u]=BG;
    CND[CPL[u]=++tot]=u;
    if(HeavySon[u])
      DFS2(HeavySon[u],u,BG);
    for(Chain *tp=Head[u];tp;tp=tp->next)
     if(tp->u!=HeavySon[u]&&tp->u!=f)
       DFS2(tp->u,u,tot+1);
    CED[u]=tot;
}

ll Query(Path X)
{
    ll res=0,u=X.f,v=X.s;
    while(CBG[v]!=CBG[u])
    {
        res+=Seg::Query(1,CBG[v],CPL[v]);
        v=F[CND[CBG[v]]];
    }
  res+=Seg::Query(1,CPL[u],CPL[v]);
  return res;
}
ll Add(ll u,ll Delta)
{
    Seg::Add(1,CPL[u],CED[u],Delta);
}

ll Div(ll x,Path Tp)
{
    if(x==K+1)return 0;
    if(Tp.f==4&&Tp.s==4)
     x++,x--;
    if(Tp.f==-1)return 0;
    ll res=Query(Tp);
    for(ll i=x+1;i<=K;i++)
    res-=Div(i,Tp&X[i]),res%=Mod;
    return res%Mod;
}
inline void ADD(ll a,ll b)
{
    Chain *tp=new Chain;
    tp->u=b,tp->next=Head[a],Head[a]=tp;
} 
ll n,Q ;
int main()
{
    read(n);
    ll i,j,k,l;
    for(i=1;i<n;i++)
    {
        read(j),read(k),ADD(j,k),ADD(k,j);
    }
    LC::DFS(1,1,1);
    DFS(1,1);
    DFS2(1,1,1);
    Seg::Build(1,1,tot);
    read(Q);
    while(Q--)
    {
        ll op;
        read(op);
        if(op)
        {
          read(K);
          ll ans=0,j,k;
           for(i=1;i<=K;i++)
             {
                read(j),read(k);
                X[i].f=Dep[j]<Dep[k]?j:k;
                X[i].s=j+k-X[i].f;
             }
          for(i=1;i<=K;i++)
           ans+=Div(i,X[i]);
        printf("%lld\n",(ans%Mod+Mod)%Mod);
       }
       else read(j),read(k),Add(j,k);
    }
//  printf("%d\n",t);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值