动态点分治系列(幻想乡战略游戏、开店、小清新数据结构题)

以上三道题在洛谷都能找到。

总结一下就是,记录分治时的父亲。
因为是子树关系的,并不关心真实的父亲是谁,所以可以放在点分树上维护两个数组来计算信息。

本文代码量超长,请谨慎食用。

这道题是入门题,比较简单。幻想乡战略游戏传送门

//幻想乡战略游戏
#include<bits/stdc++.h>
using namespace std;

const int MAXN=4e5+5;
#define ll long long
ll n,m;

struct edge{
    ll to,next,w;
}e[MAXN<<1];

struct mmap{
    ll to,next,y;
}e2[MAXN<<1]; 

ll head2[MAXN],cnt2=0;
inline void add2(ll u,ll v,ll w){e2[++cnt2]=(mmap){v,head2[u],w},head2[u]=cnt2;}

ll head[MAXN],cnt=0;
inline void add(ll u,ll v,ll w){e[++cnt]=(edge){v,head[u],w},head[u]=cnt;}

ll fa[MAXN],hson[MAXN],size[MAXN],dep[MAXN],dis[MAXN];
void dfs1(ll u,ll father){
    dep[u]=dep[father]+1;
    size[u]=1;
    fa[u]=father;
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to,w=e[i].w;
        if(v==father)continue;
        dis[v]=dis[u]+w;
        dfs1(v,u);
        size[u]+=size[v];
        if(size[v]>size[hson[u]]||!hson[u])hson[u]=v;
    }
}

ll id[MAXN],real1[MAXN],top[MAXN],num=0;
void dfs2(ll u,ll tp){
    id[u]=++num;
    top[u]=tp;
    real1[num]=u;
    if(hson[u])dfs2(hson[u],tp);
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to;
        if(v==fa[u]||v==hson[u])continue;
        dfs2(v,v);
    }
}

inline ll chain_query(ll x,ll y){
    ll tx=top[x],ty=top[y];
    ll ans=0;
    while(tx!=ty){//dep大的是在下面 
        if(dep[tx]>dep[ty]){
            x=fa[tx];
        }
        else {
            y=fa[ty];   
        }
        tx=top[x],ty=top[y];
    }
    if(dep[x]>dep[y])swap(x,y);
    return x;
}

inline ll get_dis(ll x,ll y){
    return dis[x]+dis[y]-(dis[chain_query(x,y)]<<1);
}

struct dft{
    ll sum,rt;
    ll size[MAXN],f[MAXN],par[MAXN];
    ll cost_subtree[MAXN],costfa_subtree[MAXN],dv[MAXN];//在点分树上维护这三个东西 
    bool vis[MAXN];
    void getrt(ll u,ll fa){
        size[u]=1;
        f[u]=0;
        for(ll i=head[u];i;i=e[i].next){
            ll v=e[i].to;
            if(v==fa||vis[v])continue;
            getrt(v,u);
            size[u]+=size[v];
            f[u]=max(f[u],size[v]);
        }
        f[u]=max(f[u],sum-size[u]);
        if(f[u]<f[rt])rt=u;
    }
    void solve(ll u,ll fa){
        vis[u]=1;par[u]=fa;
        for(ll i=head[u];i;i=e[i].next){
            ll v=e[i].to;
            if(vis[v])continue;
            sum=f[0]=size[v];
            getrt(v,rt=0);add2(u,rt,v);
            solve(rt,u);
        }
    }
    void change(ll u,ll val){
        dv[u]+=val;
        for(ll i=u;par[i];i=par[i]){
            ll disnum=get_dis(u,par[i]);
            cost_subtree[par[i]]+=disnum*val;
            costfa_subtree[i]+=disnum*val;
            dv[par[i]]+=val;
        }
    }
    ll calc(ll u){
        ll ans=cost_subtree[u];
        for(ll i=u;par[i];i=par[i]){
            ll disnum=get_dis(u,par[i]);
            ans+=cost_subtree[par[i]]-costfa_subtree[i];
            ans+=disnum*(dv[par[i]]-dv[i]);
        }
        return ans;
    }
    ll query(ll u){
        ll ans=calc(u);
        for(ll i=head2[u];i;i=e2[i].next){
            ll v=e2[i].to,y=e2[i].y;
            ll tem=calc(y);
            if(tem<ans)return query(v);
        }
        return ans;
    }
}dft;

int main(){
    ll oldrt;
    dft.rt=0;
    memset(dft.vis,0,sizeof(dft.vis));
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<n;i++){
        ll tem1,tem2,tem3;
        scanf("%lld%lld%lld",&tem1,&tem2,&tem3);
        add(tem1,tem2,tem3);add(tem2,tem1,tem3);
    }
    dft.sum=dft.f[0]=n;
    dft.getrt(1,0);
    oldrt=dft.rt;
    dfs1(dft.rt,dft.rt);
    dfs2(dft.rt,dft.rt);    
    dft.solve(dft.rt,0);
    for(ll i=1;i<=m;i++){
        ll tem1,tem2;
        scanf("%lld%lld",&tem1,&tem2);
        dft.change(tem1,tem2);
        printf("%lld\n",dft.query(oldrt));
    }
    return 0;
} 

开店传送门
这道题在做的时候还是很快想到前缀和去弄的。。主要是没想到用vector二分查找。
用vector去维护一个按点权的子树距离前缀和,查询的时候二分查找。代码里面有手写的upper_bound和lower_bond (我才不会说我不会用STL的呢)。

注意自己这个点也要放进去,然后重心别找错(getdis).

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const ll MAXN=4e5+5;
struct edge{
    ll to,next;ll w;
}e[MAXN<<1];

struct data{
    ll val,disn,sum;//点权
};

inline ll mymax(ll a,ll b){return a>b?a:b;}
inline ll mymin(ll a,ll b){return a>b?b:a;}

bool cmp(data a,data b){
    if(a.val==b.val)return a.disn<b.disn;
    return a.val<b.val; 
}

vector<data>sub[MAXN],subfa[MAXN];
ll head[MAXN],cnt=0;
inline void add(ll u,ll v,ll w){e[++cnt]=(edge){v,head[u],w},head[u]=cnt;}

ll n,m,A,w[MAXN<<2];

ll size[MAXN],dep[MAXN],fa[MAXN],hson[MAXN];
ll dis[MAXN];
void dfs1(ll u,ll father){
    size[u]=1;
    dep[u]=dep[father]+1;
    fa[u]=father;
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to,w=e[i].w;
        if(v==father)continue;
        dis[v]=dis[u]+w;
        dfs1(v,u);
        size[u]+=size[v];
        if(size[v]>size[hson[u]])hson[u]=v;
    }   
}

ll top[MAXN];
void dfs2(ll u,ll tp){
    top[u]=tp;
    if(hson[u])dfs2(hson[u],tp);
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to;
        if(v==fa[u]||v==hson[u])continue;
        dfs2(v,v);
    }
}

inline ll lca(ll x,ll y){
    ll tx=top[x],ty=top[y];
    while(tx!=ty){
        if(dep[tx]>dep[ty])
            x=fa[tx];
        else y=fa[ty];
        tx=top[x],ty=top[y];
    }
    if(dep[x]>dep[y])swap(x,y);
    return x;
}

ll par[MAXN],rt=0,sum=0,Size[MAXN],f[MAXN];
bool vis[MAXN];

void getrt(ll u,ll fa){
    Size[u]=1;
    f[u]=0;
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to;
        if(vis[v]||v==fa)continue;
        getrt(v,u);
        Size[u]+=Size[v];
        f[u]=max(f[u],Size[v]);
    }
    f[u]=max(f[u],sum-Size[u]);
    if(f[u]<f[rt])rt=u;
}

void get(ll u,ll fa){
    Size[u]=1;
    f[u]=0;
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to;
        if(vis[v]||v==fa)continue;
        getrt(v,u);
        Size[u]+=Size[v];
        f[u]=max(f[u],Size[v]);
    }
    f[u]=max(f[u],sum-Size[u]);
    if(f[u]<f[rt])rt=u;
}

void solve(ll u,ll fa){
    vis[u]=1;par[u]=fa;//cout<<par[u]<<"ok1"<<endl;
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to;
        if(vis[v])continue;
        get(v,0);
        sum=f[0]=Size[v];
        getrt(v,rt=0);
        solve(rt,u);
    }
}

inline ll getdis(ll x,ll y){
    return dis[x]+dis[y]-(dis[lca(x,y)]<<1);    
}

    // l 大等于中最小的-1 lower-1 
     //r 严格大于最小的-1 upper-1 

ll lower(ll u,ll sz,ll vv){
    ll l=0,r=sz-1;
    while(l+1<r){
        ll mid=(l+r)>>1;
        if(sub[u][mid].val>=vv)r=mid;
        else l=mid;
    }
    return r;
}

ll upper(ll u,ll sz,ll vv){
    ll l=0,r=sz-1;
    while(l+1<r){
        ll mid=(l+r)>>1;
        if(sub[u][mid].val>vv)r=mid;
        else l=mid;
    }
    return r;
}

ll lowerfa(ll u,ll sz,ll vv){
    ll l=0,r=sz-1;
    while(l+1<r){
        ll mid=(l+r)>>1;
        if(subfa[u][mid].val>=vv)r=mid;
        else l=mid;
    }
    return r;
}

ll upperfa(ll u,ll sz,ll vv){
    ll l=0,r=sz-1;
    while(l+1<r){
        ll mid=(l+r)>>1;
        if(subfa[u][mid].val>vv)r=mid;
        else l=mid;
    }
    return r;
}

inline ll queryr(ll u,ll v){
    ll ans=0;
    ll N=upper(u,sub[u].size(),v)-1;
    ans=sub[u][N].sum;
    for(ll i=u;par[i];i=par[i]){
        ll dist=getdis(u,par[i]);
        ll NF=upperfa(i,subfa[i].size(),v)-1;
        ll ND=upper(par[i],sub[par[i]].size(),v)-1;
        ans+=sub[par[i]][ND].sum-subfa[i][NF].sum;
        ans+=dist*(ND-NF);
    }
    return ans;
}

inline ll queryl(ll u,ll v){
    ll ans=0;
    ll N=lower(u,sub[u].size(),v)-1;
    ans=sub[u][N].sum;
    for(ll i=u;par[i];i=par[i]){
        ll dist=getdis(u,par[i]);
        ll NF=lowerfa(i,subfa[i].size(),v)-1;
        ll ND=lower(par[i],sub[par[i]].size(),v)-1;
        ans+=sub[par[i]][ND].sum-subfa[i][NF].sum;
        ans+=dist*(ND-NF);
    }
    return ans;
}

int main(){
    memset(vis,0,sizeof(vis));
    ll oldrt;
    scanf("%lld%lld%lld",&n,&m,&A);
    for(ll i=1;i<=n;i++){
        scanf("%lld",&w[i]);
    }
    for(ll i=1;i<n;i++){
        ll tem1,tem2,tem3;
        scanf("%lld%lld%lld",&tem1,&tem2,&tem3);
        add(tem1,tem2,tem3);add(tem2,tem1,tem3);
    //  cout<<"!!!"<<tem1<<":::"<<tem2<<endl;
    }
    sum=f[0]=n;
    getrt(1,rt=0);
    oldrt=rt;
    solve(rt,0);
    dfs1(oldrt,oldrt);
    dfs2(oldrt,oldrt);

    for(ll i=1;i<=n;i++){//维护节点信息,某个点权到当前点的距离。
        sub[i].push_back((data){w[i],0,0}); 
        for(ll j=i;par[j];j=par[j]){
            ll disnum=getdis(par[j],i);
            sub[par[j]].push_back((data){w[i],disnum,0});
            subfa[j].push_back((data){w[i],disnum,0});
        }
    }
    for(ll i=1;i<=n;i++){
        sub[i].push_back((data){-1,0,0});sub[i].push_back((data){1<<30,0,0});
        subfa[i].push_back((data){-1,0,0});subfa[i].push_back((data){1<<30,0,0});
        sort(sub[i].begin(),sub[i].end(),cmp);
        sort(subfa[i].begin(),subfa[i].end(),cmp);
        for(ll j=1;j<sub[i].size();j++)sub[i][j].sum=sub[i][j-1].sum+sub[i][j].disn;
        for(ll j=1;j<subfa[i].size();j++)subfa[i][j].sum=subfa[i][j-1].sum+subfa[i][j].disn;
    } 
    ll ans=0;
    for(ll i=1;i<=m;i++){
        ll tem1,tem2;ll tem3;
        scanf("%lld%lld%lld",&tem3,&tem1,&tem2);
        ll l=mymin((ans+tem1)%A,(ans+tem2)%A);
        ll r=mymax((ans+tem1)%A,(ans+tem2)%A);
        ans=queryr(tem3,r)-queryl(tem3,l);
        printf("%lld\n",ans);
    }
    return 0;
}

小清新数据结构题

这道题详细的解释见洛谷zzq神犇的题解。这题比较灵性的就是线段树那里吧,好好思考一下,我放代码跑。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const ll MAXN=4e5+5;

ll n,q,w[MAXN];
ll esum=0,ww[MAXN];

struct edge{
    ll to,next,w;
}e[MAXN<<1];

ll head[MAXN],cnt=0;
inline void add(ll u,ll v,ll w){    
    e[++cnt]=(edge){v,head[u],w},head[u]=cnt;
    e[++cnt]=(edge){u,head[v],w},head[v]=cnt;
}

ll fa[MAXN],size[MAXN],hson[MAXN],dep[MAXN],dis[MAXN];
void dfs1(ll u,ll father){
    dep[u]=dep[father]+1;
    fa[u]=father;
    size[u]=1;
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to,w=e[i].w;
        if(v==father)continue;
        dis[v]=dis[u]+w;
        dfs1(v,u);
        size[u]+=size[v];
        if(size[v]>size[hson[u]]||!hson[u])hson[u]=v;
    }
}

ll top[MAXN];
void dfs2(ll u,ll tp){
    top[u]=tp;
    if(hson[u])dfs2(hson[u],tp);
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to;
        if(v==fa[u]||v==hson[u])continue;
        dfs2(v,v);
    }
}

inline ll lca(ll x,ll y){
    ll tx=top[x],ty=top[y];
    while(tx!=ty){
        if(dep[tx]>dep[ty]) x=fa[tx];
        else y=fa[ty];
        tx=top[x],ty=top[y];
    }
    if(dep[x]>dep[y])swap(x,y);
    return x;
}

ll rsize[MAXN],f[MAXN],sum,rt,par[MAXN],sub[MAXN],subfa[MAXN];
ll sumw[MAXN],sumwfa[MAXN];
bool vis[MAXN];
void getrt(ll u,ll fa){
    rsize[u]=1;
    f[u]=0;
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to,w=e[i].w;
        if(v==fa||vis[v])continue;
        getrt(v,u);
        rsize[u]+=rsize[v];
        f[u]=max(f[u],rsize[v]);
    }
    if(f[u]<sum-rsize[u])f[u]=sum-rsize[u];
    if(f[u]<f[rt])rt=u;
}

void getsz(ll u,ll fa){
    rsize[u]=1;
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to;
        if(v==fa||vis[v])continue;
        getrt(v,u);
        rsize[u]+=rsize[v];
    }
}

void solve(ll u,ll fa){
    vis[u]=1;par[u]=fa;
    for(ll i=head[u];i;i=e[i].next){
        ll v=e[i].to;
        if(v==fa||vis[v])continue;
        getsz(v,0);
        f[0]=sum=rsize[v];
        getrt(v,rt=0);
        solve(rt,u);
    }
}

inline ll getdis(ll x,ll y){
    return dis[x]+dis[y]-(dis[lca(x,y)]<<1);
}

void memfz(){//sub为cost 
    for(ll u=1;u<=n;u++){
        sumw[u]+=w[u]; 
        for(ll i=u;par[i];i=par[i]){
            ll dist=getdis(u,par[i]);
            sumw[par[i]]+=w[u];
            sumwfa[i]+=w[u];
            sub[par[i]]+=dist*w[u];
            subfa[i]+=dist*w[u];
        }
    }
}

ll calc(ll u){
    ll ans=sub[u];
    for(ll i=u;par[i];i=par[i]){
        ll dist=getdis(par[i],u);
        ans+=sub[par[i]]-subfa[i];
        ans+=dist*(sumw[par[i]]-sumwfa[i]);
    }
    return ans+esum;
}

struct rt1tree{
    #define lson (o<<1)
    #define rson (o<<1|1)
    ll size[MAXN],dep[MAXN],fa[MAXN],hson[MAXN];
    void dfs1(ll u,ll father){
        size[u]=1;
        dep[u]=dep[father]+1;
        fa[u]=father;
        for(ll i=head[u];i;i=e[i].next){
            ll v=e[i].to;
            if(v==father)continue;
            dfs1(v,u);
            ww[u]+=ww[v];
            size[u]+=size[v];
            if(!hson[u]||size[v]>size[hson[u]])hson[u]=v;
        } 
    }
    ll id[MAXN],top[MAXN],real1[MAXN];
    ll num;
    void dfs2(ll u,ll tp){
        top[u]=tp;
        id[u]=++num;
        real1[num]=u;
        if(hson[u])dfs2(hson[u],tp);
        for(ll i=head[u];i;i=e[i].next){
            ll v=e[i].to;
            if(v==fa[u]||v==hson[u])continue;
            dfs2(v,v);
        } 
    }
    ll sumv[MAXN<<2],lzt[MAXN<<2];
    inline void pushdown(ll o,ll l,ll r){
        if(lzt[o]){
            ll mid=(l+r)>>1;
            lzt[lson]+=lzt[o];sumv[lson]+=(mid-l+1)*lzt[o];
            lzt[rson]+=lzt[o];sumv[rson]+=(r-mid)*lzt[o];
            lzt[o]=0;
        }
    }
    inline void pushup(ll o){sumv[o]=sumv[lson]+sumv[rson];}
    void build(ll o,ll l,ll r){
        lzt[o]=0;
        if(l==r){sumv[o]=ww[real1[l]];return;}
        ll mid=(l+r)>>1;
        build(lson,l,mid);
        build(rson,mid+1,r);
        pushup(o);
    }
    void change(ll o,ll l,ll r,ll ql,ll qr,ll w){
        if(ql<=l&&qr>=r){sumv[o]+=(r-l+1)*w;lzt[o]+=w;return;}
        ll mid=(l+r)>>1;
        pushdown(o,l,r);
        if(ql<=mid)change(lson,l,mid,ql,qr,w);
        if(qr>mid)change(rson,mid+1,r,ql,qr,w);
        pushup(o);
    }
    ll query(ll o,ll l,ll r,ll ql,ll qr){
        if(ql<=l&&qr>=r){return sumv[o];}
        ll mid=(l+r)>>1,ans=0;
        pushdown(o,l,r);
        if(ql<=mid)ans+=query(lson,l,mid,ql,qr);
        if(qr>mid)ans+=query(rson,mid+1,r,ql,qr);
        return ans;
    }
    inline void chain_change(ll x,ll y,ll w){
        ll tx=top[x],ty=top[y];
        while(tx!=ty){
            if(dep[tx]>dep[ty]){
                change(1,1,n,id[tx],id[x],w);
                x=fa[tx];
            }
            else {
                change(1,1,n,id[ty],id[y],w);
                y=fa[ty];
            }
            tx=top[x],ty=top[y];
        }
        if(dep[x]<dep[y])swap(x,y);
        change(1,1,n,id[y],id[x],w);
    }
    inline ll chain_query(ll x,ll y){
        ll tx=top[x],ty=top[y];
        ll ans=0;
        while(tx!=ty){
            if(dep[tx]>dep[ty]){
                ans+=query(1,1,n,id[tx],id[x]);
                x=fa[tx];
            }
            else {
                ans+=query(1,1,n,id[ty],id[y]);
                y=fa[ty];
            }
            tx=top[x],ty=top[y];
        }
        if(dep[x]<dep[y])swap(x,y);
        ans+=query(1,1,n,id[y],id[x]);
        return ans;
    }
    inline ll querysub(ll p){
        return query(1,1,n,id[p],id[p]+size[p]-1);
    }
}T;

inline void dianfen_change(ll p,ll q){
    sumw[p]+=q;
    for(ll i=p;par[i];i=par[i]){
        ll dist=getdis(p,par[i]);
        ll cost=q*dist;
        sumw[par[i]]+=q;
        sumwfa[i]+=q;
        sub[par[i]]+=cost;
        subfa[i]+=cost;
    }
}

int main(){
    ll oldrt,wfang=0;
    T.num=0;
    memset(vis,0,sizeof(vis));
    scanf("%lld%lld",&n,&q);
    for(ll i=1;i<n;i++){
        ll tem1,tem2;
        scanf("%lld%lld",&tem1,&tem2);
        add(tem1,tem2,1);
    }
    for(ll i=1;i<=n;i++){
        scanf("%lld",&w[i]);
        ww[i]=w[i];
        esum+=w[i];
    }
    sum=f[0]=n;
    getrt(1,rt=0);
    oldrt=rt;
    solve(rt,0);
    dfs1(oldrt,oldrt);
    dfs2(oldrt,oldrt);  
    memfz();
    T.dfs1(1,1);
    T.dfs2(1,1);
    T.build(1,1,n);
    for(ll i=1;i<=n;i++)wfang+=T.chain_query(i,i)*T.chain_query(i,i);
    for(ll i=1;i<=q;i++){
        ll tem1,tem2,tem3;
        scanf("%lld%lld",&tem1,&tem2);
        if(tem1==1){
            scanf("%lld",&tem3);
            ll q=tem3-w[tem2];
            esum+=q;
            w[tem2]=tem3;
            ll p=T.chain_query(1,tem2);
            wfang+=((p*q)<<1)+(getdis(1,tem2)+1)*q*q;
            T.chain_change(1,tem2,q);
            dianfen_change(tem2,q);
        }
        else {
            ll g=calc(1);
            g*=esum;
            g-=wfang;
            ll ww=calc(tem2);
            ww*=esum;
            ww-=g;
            printf("%lld\n",ww);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值