BZOJ 3924: [Zjoi2015]幻想鄉戰略游戲(動態點分治)


這種動態點分治嘛,GDKOI時聽打到了,也有同學講到了,所以印象比較深刻也就想出來了,然后就在實現方面卡了好久= =

不得不說CLJ說得真的太簡單了,實現方面根本沒提。

首先我們可以先用樹分治構建出這棵樹的分治樹,也就是把這棵樹的重心作為根節點然后子樹為他的子樹的重心這樣遞歸下去,然后每個節點存的是其子樹的信息。

對於每個節點我們保存這個子樹的dv的總和已經把該節點作為點的答案值

這樣對於修改能在log n的時間內解決

尋找答案的時候,我們可以發現,如果現在節點的子樹dv和*2大於總節點,那么向那個方向過去一定比原方案好

我們先從根節點開始,若發現答案在某棵子樹時,我們考慮如何使其兒子節點的答案轉變為整個樹的答案,可以發現把除這個子樹外的所有節點可以縮成一個節點並連在這棵子樹上,然后就可以一直這樣做下去,找到操作之后再把這些撤銷

因此還是得維護一些奇奇怪怪的東西,但打出來還是挺短的

Code:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 100100
typedef long long ll;
typedef pair<ll,ll> ii;
typedef pair<ll,ii> iii;
#define fi first
#define se second
#define pb push_back
struct edges{int to,next,dist;}edge[maxn*2];
int l,next[maxn];
inline void addedge(int x,int y,int z) {
    edge[++l]=(edges){y,next[x],z};next[x]=l;
    edge[++l]=(edges){x,next[y],z};next[y]=l;
}
bool done[maxn];
int s[maxn],f[maxn],root,size;
void dfs(int u,int fa){
    s[u]=1;f[u]=0;
    int v=0;
    for (int i=next[u];i;i=edge[i].next) {
        if (done[v=edge[i].to]||v==fa) continue;
        dfs(v,u);
        s[u]+=s[v];
        f[u]=max(f[u],s[v]);
    }
    f[u]=max(f[u],size-s[u]);
    if (f[u]<f[root]) root=u;
}
vector<ii> pre[maxn];
void getdist(int u,int fa,int tar,int dist) {
    pre[u].pb(ii(tar,dist));
    s[u]=1;int v=0;
    for (int i=next[u];i;i=edge[i].next) {
        if (done[v=edge[i].to]||v==fa) continue;
        getdist(v,u,tar,dist+edge[i].dist);
        s[u]+=s[v];
    }
}
vector<iii> ch[maxn];
void work(int u){
    done[u]=1;
    int v=0;
    pre[u].pb(ii(u,0));
    for (int i=next[u];i;i=edge[i].next) {
        if (done[v=edge[i].to]) continue;
        getdist(v,0,u,edge[i].dist);
        f[0]=size=s[v];
        dfs(v,root=0);
        ch[u].pb(iii(root,ii(v,edge[i].dist)));
        work(root);
    }
}
ll cnt[maxn],sum[maxn];
vector<ll> sumdist[maxn];
inline void update(int x,ll y,ll z){
    for (int i=0;i<pre[x].size();i++) {
        int u=pre[x][i].fi;
        cnt[u]+=y;sum[u]+=z+y*pre[x][i].se;
        if (i!=pre[x].size()-1) {
            int j=0;
            for (;j<ch[u].size();j++) 
                if (ch[u][j].fi==pre[x][i+1].fi) sumdist[u][j]+=z+y*pre[x][i].se;
        }
    }
}
int realroot;
vector<iii> record;
inline ll query(){
    int x=realroot;
    int mx=0;
    record.clear();
    while (x){
        mx=0;
        for (int i=1;i<ch[x].size();i++) 
            if (cnt[ch[x][mx].fi]<cnt[ch[x][i].fi]) mx=i;
        if (ch[x].size()==0||cnt[ch[x][mx].fi]*2<=cnt[x]) {
            ll ans=sum[x];
            for (int i=0;i<record.size();i++) 
                update(record[i].fi,record[i].se.fi,record[i].se.se);
            return ans;
        }
        int v=ch[x][mx].fi;
        record.pb(iii(ch[x][mx].se.fi,ii(-(cnt[x]-cnt[v]),
                -(sum[x]-sumdist[x][mx]+(cnt[x]-cnt[v])*ch[x][mx].se.se))));
        update(ch[x][mx].se.fi,cnt[x]-cnt[v],
                sum[x]-sumdist[x][mx]+(cnt[x]-cnt[v])*ch[x][mx].se.se);
        x=v;
    }
}
int main(){
    int n,Q;
    scanf("%d%d",&n,&Q);
    for (int i=1;i<n;i++) {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        addedge(x,y,z);
    }
    f[0]=size=n;
    dfs(1,root=0);
    realroot=root;
    work(root);
    for (int i=1;i<=n;i++) sumdist[i]=vector<ll>(ch[i].size(),0);
    while (Q--) {
        int x,y;
        scanf("%d%d",&x,&y);
        update(x,y,0);
        printf("%lld\n",query());
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM