P3313 [SDOI2014]旅行(动态开点线段树+树链剖分)

这题如果直接做,显然是是对每个信仰维护一棵线段树,但是这样铁定炸内存,因此考虑使用动态开点线段树

这样的答案就和询问的个数相关。之后就是普通的树链剖分维护

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pll;
const int N=2e5+10;
const int M=2e6+10;
const int inf=0x3f3f3f3f;
const ll mod=998244353;
int id[N],w[N],dfn[N],top[N],h[N],e[N],ne[N],idx,times;
int fa[N],sz[N],son[N],depth[N],rt[N];
int c[N];
int tot,n;
ll ans;
struct node{
    int l,r;
    int sum;
    int mx;
}tr[N*24];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u){//算父亲和重儿子
    int i;
    sz[u]=1;
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==fa[u])
            continue;
        fa[j]=u;
        depth[j]=depth[u]+1;
        dfs(j);
        sz[u]+=sz[j];
        if(sz[j]>sz[son[u]]){
            son[u]=j;
        }
    }
}
void dfs1(int u,int x){
    dfn[u]=++times;
    id[times]=u;
    top[u]=x;
    if(!son[u])
        return ;
    dfs1(son[u],x);
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==son[u]||j==fa[u])
            continue;
        dfs1(j,j);
    }
}
void pushup(int u){
    int l=tr[u].l,r=tr[u].r;
    tr[u].mx=max(tr[l].mx,tr[r].mx);
    tr[u].sum=tr[l].sum+tr[r].sum;
}
void pushdown(int u){
    tr[u].mx=tr[u].sum=0;
}
void modify(int &u,int x,int l,int r,int v){
    if(!u) u=++tot;
    if(l==r){
        tr[u].sum=tr[u].mx=v;
        return ;
    }
    int mid=l+r>>1;
    if(x<=mid) modify(tr[u].l,x,l,mid,v);
    else modify(tr[u].r,x,mid+1,r,v);
    pushup(u);
}
void del(int &u,int x,int l,int r){
    if(!u) return ;
    if(l==r){
        pushdown(u);
        u=0;
        return ;
    }
    int mid=l+r>>1;
    if(x<=mid) del(tr[u].l,x,l,mid);
    else del(tr[u].r,x,mid+1,r);
    pushup(u);
}
ll query_sum(int &u,int L,int R,int l,int r){
    if(!u) return 0;
    if(L<=l&&r<=R){
        return tr[u].sum;
    }
    ll ans=0;
    int mid=l+r>>1;
    if(L<=mid) ans+=query_sum(tr[u].l,L,R,l,mid);
    if(R>mid) ans+=query_sum(tr[u].r,L,R,mid+1,r);
    return ans;
}
ll query_mx(int &u,int L,int R,int l,int r){
    if(!u) return 0;
    if(L<=l&&r<=R){
        return tr[u].mx;
    }
    ll ans=0;
    int mid=l+r>>1;
    if(L<=mid) ans=max(ans,query_mx(tr[u].l,L,R,l,mid));
    if(R>mid) ans=max(ans,query_mx(tr[u].r,L,R,mid+1,r));
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    int q;
    cin>>n>>q;
    int i;
    memset(h,-1,sizeof h);
    for(i=1;i<=n;i++)
        cin>>w[i]>>c[i];
    for(i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    dfs(1);
    dfs1(1,1);
    for(i=1;i<=n;i++){
        modify(rt[c[id[i]]],i,1,n,w[id[i]]);
    }
    string s;
    while(q--){
        cin>>s;
        int x,y;
        if(s[1]=='C'){
            cin>>x>>y;
            del(rt[c[x]],dfn[x],1,n);
            c[x]=y;
            modify(rt[c[x]],dfn[x],1,n,w[x]);
        }
        if(s[1]=='W'){
            cin>>x>>y;
            del(rt[c[x]],dfn[x],1,n);
            w[x]=y;
            modify(rt[c[x]],dfn[x],1,n,w[x]);
        }
        if(s[1]=='S'){
            cin>>x>>y;
            int k=c[x];
            ans=0;
            while(top[x]!=top[y]){
                if(depth[top[x]]<depth[top[y]])
                    swap(x,y);
                ans+=query_sum(rt[k],dfn[top[x]],dfn[x],1,n);
                x=fa[top[x]];
            }
            if(depth[x]>depth[y])
                swap(x,y);
            ans+=query_sum(rt[k],dfn[x],dfn[y],1,n);
            cout<<ans<<endl;
        }
        if(s[1]=='M'){
            cin>>x>>y;
            int k=c[x];
            ans=0;
            while(top[x]!=top[y]){
                if(depth[top[x]]<depth[top[y]])
                    swap(x,y);
                ans=max(ans,query_mx(rt[k],dfn[top[x]],dfn[x],1,n));
                x=fa[top[x]];
            }
            if(depth[x]>depth[y])
                swap(x,y);
            ans=max(ans,query_mx(rt[k],dfn[x],dfn[y],1,n));
            cout<<ans<<endl;
        }
    }
    return 0;
}
View Code

 

posted @ 2020-09-07 11:34  朝暮不思  阅读(162)  评论(0编辑  收藏  举报