【JZOJ 4488】【GDOI 2016 Day1】第四题 疯狂动物城

Description

给出一个N个节点的数,和M次操作。每次操作的类型如下:
1,x,y,z,将x到y的路径上的ai加上z
2,x,y,询问x到y的路径上,ai*(1+2+..+n-i)的和
3,x,将所有的a变更回第x次修改之后的状态。
强制在线。
N,M<=10^5.

Analysis

裸题——码农一道!
可持久化线段树+树链剖分兹磁树上的区间查询&修改。
代码量飞飞飞飞起~
至于区间合并请自行脑补。

Code

#include<cstdio>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,b,a) for(int i=b;i>=a;i--)
#define efo(i,v) for(int i=last[v];i;i=next[i])
using namespace std;
typedef long long ll;
const int N=100010,M=N*2,mo=20160501,ny=10080251;
int n,m,num,tot,now,to[M],next[M],last[N],root[N];
int son[N],fa[N],top[N],size[N],w[N],re[N],f[N][18];
ll c[N],dep[N];
struct node
{
    int l,r;
    ll lz,ad2,ad,ai,d,d2;
}a[N*60];
void link(int u,int v)
{
    to[++tot]=v,next[tot]=last[u],last[u]=tot;
}
void dfs1(int v,int from,int d)
{
    size[v]=1,dep[v]=d;
    int k=0;
    efo(i,v)
    {
        int u=to[i];
        if(u==from) continue;
        dfs1(u,v,d+1);
        size[v]+=size[u],fa[u]=f[u][0]=v;
        if(size[u]>size[k]) k=u;
    }
    son[v]=k;
}
void dfs2(int v,int from,int p)
{
    top[v]=p,w[v]=++num,re[num]=v;
    if(!son[v]) return;
    dfs2(son[v],v,p);
    efo(i,v)
    {
        int u=to[i];
        if(u==from || u==son[v]) continue;
        dfs2(u,v,u);
    }
}
int getlca(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    fd(i,int(log2(dep[u])),0)
        if(dep[f[u][i]]>=dep[v]) u=f[u][i];
    fd(i,int(log2(dep[u])),0)
        if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
    if(u!=v) return f[u][0];
    return u;
}
void up(int v)
{
    a[v].ai=(a[a[v].l].ai+a[a[v].r].ai)%mo;
    a[v].ad=(a[a[v].l].ad+a[a[v].r].ad)%mo;
    a[v].ad2=(a[a[v].l].ad2+a[a[v].r].ad2)%mo;
}
void down(int v,int l,int r)
{
    if(!a[v].lz) return;
    ll k=a[v].lz;
    int mid=(l+r)>>1;
    a[++m]=a[a[v].l],(a[m].ai+=k*(mid-l+1))%=mo,(a[m].ad+=k*a[m].d)%=mo,(a[m].ad2+=k*a[m].d2)%=mo,a[m].lz+=k;
    a[v].l=m;
    a[++m]=a[a[v].r],(a[m].ai+=k*(r-mid))%=mo,(a[m].ad+=k*a[m].d)%=mo,(a[m].ad2+=k*a[m].d2)%=mo,a[m].lz+=k;
    a[v].r=m;
    a[v].lz=0;
}
void build(int &v,int l,int r)
{
    v=++m;
    if(l==r)
    {
        a[v].ai=c[re[l]],a[v].ad=c[re[l]]*dep[re[l]]%mo,a[v].ad2=c[re[l]]*dep[re[l]]*dep[re[l]]%mo;
        a[v].d=dep[re[l]];a[v].d2=a[v].d*dep[re[l]]%mo;
        return;
    }
    int mid=(l+r)>>1;
    build(a[v].l,l,mid);
    build(a[v].r,mid+1,r);
    up(v);
    a[v].d=a[a[v].l].d+a[a[v].r].d;
    a[v].d2=a[a[v].l].d2+a[a[v].r].d2;
}
ll query(int v,int l,int r,int x,int y,ll t)
{
    if(l==x && r==y) return ((a[v].ad2+a[v].ad*(2*t+1)%mo+a[v].ai*t*(t+1)%mo)%mo+mo)%mo;
    down(v,l,r);
    int mid=(l+r)>>1;
    if(x>mid) return query(a[v].r,mid+1,r,x,y,t);
    else
    if(y<=mid) return query(a[v].l,l,mid,x,y,t);
    else return (query(a[v].l,l,mid,x,mid,t)+query(a[v].r,mid+1,r,mid+1,y,t))%mo;
}
ll solve(int x,int y,int k)
{
    ll ans=0;
    int len=0,p,u=x,v=y,lca=getlca(x,y);
    while(top[u]!=top[v])
    {
        if(dep[top[u]]>dep[top[v]])
        {
            p=top[u];
            (ans+=query(root[k],1,n,w[p],w[u],dep[y]-2*dep[lca]))%=mo;
            u=fa[p];
        }
        else
        {
            p=top[v];
            (ans+=query(root[k],1,n,w[p],w[v],-dep[y]-1))%=mo;
            v=fa[p];
        }
    }
    if(dep[u]>=dep[v]) (ans+=query(root[k],1,n,w[v],w[u],dep[y]-2*dep[lca]))%=mo;
    else (ans+=query(root[k],1,n,w[u],w[v],-dep[y]-1))%=mo;
    return ans;
}
void modify(int u,int &v,int l,int r,int x,int y,ll z)
{
    down(u,l,r);
    if(u==v) a[v=++m]=a[u]; 
    if(l==x && r==y)
    {
        (a[v].ai+=z*(r-l+1))%=mo,a[v].lz+=z;
        (a[v].ad+=z*a[v].d)%=mo;
        (a[v].ad2+=z*a[v].d2)%=mo;
        return;
    }
    int mid=(l+r)>>1;
    if(x>mid) modify(a[u].r,a[v].r,mid+1,r,x,y,z);
    else
    if(y<=mid) modify(a[u].l,a[v].l,l,mid,x,y,z);
    else
    modify(a[u].l,a[v].l,l,mid,x,mid,z),modify(a[u].r,a[v].r,mid+1,r,mid+1,y,z);
    up(v);
}
void change(int u,int v,int k,ll z)
{
    if(!root[k]) root[k]=root[now];
    int x;
    while(top[u]!=top[v])
    {
        if(dep[top[u]]>dep[top[v]]) swap(u,v);
        x=top[v];
        modify(root[now],root[k],1,n,w[x],w[v],z);
        v=fa[x];
    }
    if(dep[u]>dep[v]) swap(u,v);
    modify(root[now],root[k],1,n,w[u],w[v],z);
}
int main()
{
    freopen("zootopia.in","r",stdin);
    freopen("zootopia.out","w",stdout);
    int _,tp,x,y,z,k=0;
    ll ans=0;
    scanf("%d %d",&n,&_);
    fo(i,1,n-1)
    {
        scanf("%d %d",&x,&y);
        link(x,y),link(y,x);
    }
    fo(i,1,n) scanf("%lld",&c[i]);
    dfs1(1,0,1);
    dfs2(1,0,1);
    fo(j,1,int(log2(n)))
        fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
    build(root[0],1,n);
    while(_--)
    {
        scanf("%d %d",&tp,&x);
        x^=ans;
        if(tp==1)
        {
            scanf("%d %d",&y,&z);
            y^=ans;
            change(x,y,++k,z);
            now=k;
        }
        else
        if(tp==2)
        {
            scanf("%d",&y);
            y^=ans;
            ans=solve(x,y,now)*ny%mo;
            printf("%lld\n",ans);
        }
        else now=x;
    }
    fclose(stdin);fclose(stdout);
    return 0;
}

你可能感兴趣的:(码农,树链剖分,可持久化线段树)