牛客 - A National Pandemic


传送门:牛客 - A National Pandemic

树链剖分

对于2操作,记录一个delta数组就行了
对于1操作,将式子拆开:$w-dep[x]-dep[y]+2*dep[lca(x,y)]$,前面的都很好处理,主要是这个$lca$的部分,显然$lca$一定是$x$到$1$这条路径上的点,将这条路径上的权值加上$2$,那么对$y$的影响就是1到y这条路上的权值和了

AC代码


#include <bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define mp make_pair
#define fun function
#define sz(x) (x).size()
#define lowbit(x) (x)&(-x)
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))

namespace FastIO {
#define BUF_SIZE 100000
#define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc() {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if(p1==pend) {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if(pend==p1) {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) {
        return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';
    }
    template<class T> inline bool read(T &x) {
        bool sign=0;
        char ch=nc();
        x=0;
        for(; blank(ch); ch=nc());
        if(IOerror)return false;
        if(ch=='-')sign=1,ch=nc();
        for(; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if(sign)x=-x;
        return true;
    }
    template<class T,class... U>bool read(T& h,U&... t) {
        return read(h)&&read(t...);
    }
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace std;
using namespace FastIO;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int INF = 0x3f3f3f3f;
const int N = 5e4+10;

vector<int>e[N];
int dfn[N],top[N],siz[N],son[N],dep[N],fa[N],tim;

void dfs1(int u,int f){
    dep[u]=dep[f]+1;
    fa[u]=f;
    siz[u]=1;
    for(auto v:e[u]){
        if(v==f) continue;
        dfs1(v,u);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]]) son[u]=v;
    }
} 

void dfs2(int u,int t){
    top[u]=t;
    dfn[u]=++tim;
    if(!son[u]) return ;
    dfs2(son[u],t);
    for(auto v:e[u]){
        if(v==fa[u] || v==son[u]) continue;
        dfs2(v,v);
    }
}

struct node{
    int l,r,mid,sum,lazy,len;
}tree[N<<2];

#define ls x<<1
#define rs x<<1|1
void pp(int x){
    tree[x].sum=tree[ls].sum+tree[rs].sum;
}

void build(int x,int l,int r){
    tree[x]={l,r,l+r>>1,0,0,r-l+1};
    if(l==r) return ;
    int mid=tree[x].mid;
    build(ls,l,mid);
    build(rs,mid+1,r);
}

void pd(int x){
    if(tree[x].lazy){
        int now=tree[x].lazy;
        tree[ls].lazy+=now;
        tree[rs].lazy+=now;
        
        tree[ls].sum+=tree[ls].len*now;
        tree[rs].sum+=tree[rs].len*now;
        
        tree[x].lazy=0;
    }
}

void modify(int x,int l,int r,int k){
    if(l<=tree[x].l && tree[x].r<=r){
        tree[x].lazy+=k;
        tree[x].sum+=k*tree[x].len;
        return ;
    }
    pd(x);
    int mid=tree[x].mid;
    if(l<=mid) modify(ls,l,r,k);
    if(r>mid) modify(rs,l,r,k);
    pp(x);
}

int query(int x,int l,int r){
    if(l<=tree[x].l && tree[x].r<=r){
        return tree[x].sum;
    }
    pd(x);
    int ans=0;
    int mid=tree[x].mid;
    if(l<=mid) ans+=query(ls,l,r);
    if(r>mid) ans+=query(rs,l,r);
    return ans;
}

void change(int x,int y,int k){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        modify(1,dfn[top[x]],dfn[x],k);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    modify(1,dfn[x],dfn[y],k);
}

int Query(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans+=query(1,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ans+=query(1,dfn[x],dfn[y]);
    return ans;
}

int totadd,cnt,delta[N];

int getsum(int x){
    return totadd-cnt*dep[x]+Query(1,x)-delta[x];
}

int n,m;
void init(){
    totadd=0;
    cnt=0;
    tim=0;
    for(int i=1;i<=n;i++){
        e[i].clear();
        delta[i]=0;
        son[i]=0;
    }
    build(1,1,n);
}

int main() {

#ifdef xiaofan
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
#endif

    int T;
    read(T);
    while(T--){
        read(n,m);
        init();
        for(int i=1;i<n;i++){
            int u,v;
            read(u,v);
            e[u].pb(v);
            e[v].pb(u);
        }
        dfs1(1,0);
        dfs2(1,1);
        while(m--){
            int op,x,w;
            read(op,x);
            if(op==1){
                read(w);
                totadd+=w-dep[x];
                cnt++;
                change(1,x,2);
            }
            if(op==2){
                int now=getsum(x);
                if(now>0) delta[x]+=now;
            }
            if(op==3){
                printf("%d\n",getsum(x));
            }
        }    
    }




    return 0;
}

动态点分治

对于2操作,记录一个delta数组就行了
对于1操作,建立点分树,维护权值和以及修改点数量,容斥计算答案

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define fun function
#define sz(x) (x).size()
#define lowbit(x) (x)&(-x)
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))

namespace FastIO {
#define BUF_SIZE 100000
#define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc() {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if(p1==pend) {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if(pend==p1) {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) {
        return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';
    }
    template<class T> inline bool read(T &x) {
        bool sign=0;
        char ch=nc();
        x=0;
        for(; blank(ch); ch=nc());
        if(IOerror)return false;
        if(ch=='-')sign=1,ch=nc();
        for(; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if(sign)x=-x;
        return true;
    }
    template<class T,class... U>bool read(T& h,U&... t) {
        return read(h)&&read(t...);
    }
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace std;
using namespace FastIO;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
#define int long long
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;

const int INF = 0x3f3f3f3f;
const int N = 5e4+10;

vector<int>e[N];

struct Grand_Father {
    int deep[N], euler[N << 1], esiz, rid[N],log_2[N<<1];
    void dfs(int u, int fa) {
        deep[u] = deep[fa] + 1;
        rid[u] = esiz + 1;
        for(auto v:e[u]) {
            if(v == fa) continue;
            euler[++esiz] = u;
            dfs(v, u);
        }
        euler[++esiz] = u;
    }
    int mn[N << 1][23];

    inline void rmq_init() {
        if(!log_2[2]) for(int i=2; i<N*2; i++) log_2[i] = log_2[i >> 1] + 1;
        for(int i=1; i<=esiz; i++) mn[i][0] = euler[i];
        for(int j=1; (1 << j) <= esiz; j++) {
            for(int i=1; i + (1 << j) - 1 <= esiz; i++) {
                if(deep[mn[i][j - 1]] < deep[mn[i + (1 << (j - 1))][j - 1]]) mn[i][j] = mn[i][j - 1];
                else mn[i][j] = mn[i + (1 << (j - 1))][j - 1];
            }
        }
    }
    void solve(int s) {
        esiz = 0;
        dfs(s, 0);
        rmq_init();
    }
    inline int rmq(int l, int r) {
        int det = r - l + 1, kk = log_2[det];
        if(deep[mn[l][kk]] <= deep[mn[r - (1 << kk) + 1][kk]]) return mn[l][kk];
        else return mn[r - (1 << kk) + 1][kk];
    }
    inline int lca(int u, int v) {
        int l = rid[u], r = rid[v];
        if(l > r) swap(l, r);
        return rmq(l, r);
    }
    inline int dis(int u, int v) {
        return deep[u] + deep[v] - 2 * deep[lca(u,v)];
    }
} LCA;

int dis(int x,int y) {
    return LCA.dis(x,y);
}

int siz[N],tot,root,maxp[N],dfa[N];
bool vis[N];

void getroot(int u,int f) {
    siz[u] = 1;
    maxp[u] = 0;
    for(auto v:e[u]) {
        if(v==f || vis[v]) continue;
        getroot(v,u);
        siz[u]+=siz[v];
        maxp[u] = max(maxp[u],siz[v]);
    }
    maxp[u] = max(maxp[u],tot-siz[u]);
    if(maxp[u]<maxp[root]) root = u;
}


void div(int u) {
    vis[u] = true;
    int all = tot;
    for(auto v:e[u]) {
        if(vis[v]) continue;
        tot=siz[v]>siz[u]? all - siz[u]:siz[v];
        root=0;
        maxp[root] = tot;
        getroot(v,u);
        dfa[root] = u;
        div(root);
    }
}

int s1[N],cnt1[N];
int s2[N],cnt2[N];
int delta[N];

void modify(int idx,int val) {
    int now = idx;
    while(now) {
        int f = dfa[now];
        s1[now] += val - dis(idx,now);
        cnt1[now]++;
        if(f) {
            s2[now] += val - dis(idx,f);
            cnt2[now]++;
        }
        now = f;
    }
}

int query(int idx) {
    int ans = -delta[idx];
    int now = idx,last = 0;
    while(now) {
        ans+=s1[now];
        if(last) {
            ans -= s2[last];
            ans -= (cnt1[now] - cnt2[last])*dis(now,idx);
        }
        last = now;
        now = dfa[now];
    }
    return ans;
}

int n,m;

void init() {
    LCA.solve(1);
    root = 0;
    tot = n;
    maxp[root] = tot;
    getroot(1,1);
    div(root);
}

void prework() {
    for(int i=1; i<=n; i++) {
        e[i].clear();
        delta[i] = 0;
        dfa[i] = 0;
        vis[i] = false;
        s1[i] = cnt1[i] = 0;
        s2[i] = cnt2[i] = 0;
    }

    for(int i=1; i<n; i++) {
        int u,v;
        read(u,v);
        e[u].pb(v);
        e[v].pb(u);
    }
}



signed main() {

#ifdef xiaofan
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
#endif

    int T;
    read(T);
    while(T--) {
        read(n,m);
        prework();
        init();
        while(m--) {
            int op,x,y;
            read(op,x);
            if(op == 1) {
                read(y);
                modify(x,y);
            }
            if(op == 2) {
                int val = query(x);
                if(val>0) delta[x]+=val;
            }
            if(op == 3) {
                printf("%lld\n",query(x));
            }
        }
    }




    return 0;
}



文章作者: 小凡
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小凡 !
评论
  目录
隐藏
{% if theme.sakura.enable %}{% endif %}