2021牛客暑期多校训练营3 G-Yu Ling(Ling YueZheng) and Colorful Tree(cdq分治)

G-Yu Ling(Ling YueZheng) and Colorful Tree

HOWARLI题解

大致做法就是首先考虑哪些修改可能影响询问,当修改点权是询问的倍数时才可能影响询问。于是考虑把他们放在一起。

首先每次枚举每种询问的倍数,把这些修改和当前询问放在一起,由于每次考虑的是该点到根节点路径上的点,对于每个点的点权的修改仅仅影响的子树节点的询问。于是将单点修改 → \to 子树修改,链询问 → \to 单点询问。

于是每次修改转化成 [ dfn u , dfn u + sz u − 1 ] [\text{dfn}_u,\text{dfn}_u+\text{sz}_u-1] [dfnu,dfnu+szu1]添加一个 [ x , dis u ] [x,\text{dis}_u] [x,disu]即可以表示成插入 { id , dfn u → dfn u + sz u − 1 , x } = dis u \{\text{id},\text{dfn}_u \to \text{dfn}_u+\text{sz}_u-1,x\} = \text{dis}_u {id,dfnudfnu+szu1,x}=disu

于是询问的问题转化成 dfn u \text{dfn}_u dfnu处询问 [ [ l , r ] , max ⁡ { dis u } ] [[l,r],\max\{\text{dis}_u\}] [[l,r],max{disu}]可以表示成询问 max ⁡ { { id , dfn u , l → r } = dis } \max\{\{\text{id},\text{dfn}_u,l\to r\}=\text{dis}\} max{{id,dfnu,lr}=dis}

现在相当于有三维 [ id , dfn , val ] [\text{id},\text{dfn},\text{val}] [id,dfn,val],即空间上的一个点,点权是 dis \text{dis} dis,显然可以树套树或者cdq分治。

分析一下就可以知道上述求的 max ⁡ dis \max \text{dis} maxdis一定是离 u u u最近的。
下面代码用cdq分治。不过wtcl还没调出来~~

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{
    T res=0;T fg=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}
    while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    return res*fg;
}
const int N=110005;
int h[N],e[2*N],ne[2*N],idx;
ll w[2*N];
void add(int a,int b,ll c){e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;}

int n,m;
struct node1
{
    int op,u,x;
    int l,r;
}q[N];
struct node2
{
    int op,id;
    int t,l,r;
    ll x;
}q0[N<<1];
int dfn[N],timestamp;
ll dis[N];
int sz[N];
void dfs(int u,int fa)
{
    dfn[u]=++timestamp;
    sz[u]=1;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int v=e[i];
        if(v==fa) continue;
        dis[v]=dis[u]+w[i];
        dfs(v,u);
        sz[u]+=sz[v];
    }
}
vector<int> V0[N],V1[N];
ll v[N<<2];
ll ans[N];
void modify(int u,int l,int r,int pos,ll x)
{
    if(l==r) return v[u]=x,void();
    
    int mid=l+r>>1;
    if(pos<=mid) 
        modify(u<<1,l,mid,pos,x);
    else   
        modify(u<<1|1,mid+1,r,pos,x);
    v[u]=max(v[u<<1],v[u<<1|1]);
}
ll query(int u,int l,int r,int L,int R)
{
    if(L<=l&&r<=R) return v[u];
    int mid=l+r>>1;
    ll c=-1;
    if(L<=mid) 
        c=max(c,query(u<<1,l,mid,L,R));
    if(R>mid)
        c=max(c,query(u<<1|1,mid+1,r,L,R));
    return c;
}
void solve(int l,int r)
{
    if(l>=r) return;
    int mid=l+r>>1;
    solve(l,mid),solve(mid+1,r);
    
    int i=l;
    for(int j=mid+1;j<=r;j++)
    {
        while(i<=mid&&q0[i].t<=q0[j].t)
        {
            if(q0[i].op==0) modify(1,1,n,q0[i].l,q0[i].x);
            i++;
        }
        if(q0[j].op==1) ans[q0[j].id]=max(ans[q0[j].id],query(1,1,n,q0[j].l,q0[j].r));
    }
    while(i>l) 
    {
        --i;
        if(q0[i].op==0) modify(1,1,n,q0[i].l,-1);
    }
    
    inplace_merge(q0+l,q0+mid+1,q0+r+1,[](const node2&a,const node2&b){return a.t<b.t;});
}
int main()
{
    n=rd(),m=rd();
    memset(h,-1,sizeof h);
    memset(v,-1,sizeof v);
    memset(ans,-1,sizeof ans);
    
    for(int i=1;i<n;i++) 
    {
        int u=rd(),v=rd(),c=rd();
        add(u,v,c),add(v,u,c);
    }
    
    for(int i=1;i<=m;i++)
    {
        q[i].op=rd();
        q[i].u=rd();
        if(q[i].op) 
        {
            q[i].l=rd(),q[i].r=rd(),q[i].x=rd();
            V1[q[i].x].push_back(i);
        }
        else 
        {
            q[i].x=rd();
            V0[q[i].x].push_back(i);
        }
    }
    
    dfs(1,0);
    
    int cnt;
    for(int i=1;i<=n;i++)
    {
        if(V1[i].empty()) continue;
        cnt=0;
        for(int j=i;j<=n;j+=i)
        {
            for(int k:V0[j])
            {
                int u=q[k].u;
                q0[++cnt]={0,k,dfn[u],j,j,dis[u]};
                q0[++cnt]={0,k,dfn[u]+sz[u],j,j,-1};
            }
        }
        if(!cnt) continue;
        for(int k:V1[i])
        {
            int u=q[k].u,l=q[k].l,r=q[k].r;
            q0[++cnt]={1,k,dfn[u],l,r};
        }
        sort(q0+1,q0+1+cnt,[](const node2& a,const node2 &b){return a.id<b.id||a.id==b.id&&a.op<b.op;});
        solve(1,cnt);
    }
    
    
    for(int i=1;i<=m;i++)
    {
        if(q[i].op==0) continue;
        if(ans[i]==-1)
            puts("Impossible!");
        else
            printf("%lld\n",dis[q[i].u]-ans[i]);
    }
}

上面代码有大问题

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{
    T res=0;T fg=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}
    while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    return res*fg;
}
const int N=110005;
int h[N],e[2*N],ne[2*N],idx;
ll w[2*N];
void add(int a,int b,ll c){e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;}

int n,m;
struct node1
{
    int op,u,x;
    int l,r;
}q[N];
struct node2
{
    int op,id;
    int t,l,r;
    ll x;
}q0[N<<1];
int dfn[N],timestamp;
ll dis[N];
int sz[N];
void dfs(int u,int fa)
{
    dfn[u]=++timestamp;
    sz[u]=1;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int v=e[i];
        if(v==fa) continue;
        dis[v]=dis[u]+w[i];
        dfs(v,u);
        sz[u]+=sz[v];
    }
}
vector<int> V0[N],V1[N];
ll v[N<<2];
ll ans[N];
void modify(int u,int l,int r,int pos,ll x)
{
    if(l==r) return v[u]=x,void();
    
    int mid=l+r>>1;
    if(pos<=mid) 
        modify(u<<1,l,mid,pos,x);
    else   
        modify(u<<1|1,mid+1,r,pos,x);
    v[u]=max(v[u<<1],v[u<<1|1]);
}
ll query(int u,int l,int r,int L,int R)
{
    if(L<=l&&r<=R) return v[u];
    int mid=l+r>>1;
    ll c=-1;
    if(L<=mid) 
        c=max(c,query(u<<1,l,mid,L,R));
    if(R>mid)
        c=max(c,query(u<<1|1,mid+1,r,L,R));
    return c;
}

struct node3
{
    int id;
    ll v;
    node3(){}
    node3(int id,ll v):id(id),v(v){}
    bool operator<(const node3&o)const
    {
        return v>o.v||v==o.v&&id<o.id;
    }
};
multiset<node3> mp[N];
multiset<node3>::iterator it;
void solve(int l,int r)
{
    if(l>=r) return;
    int mid=l+r>>1;
    solve(l,mid),solve(mid+1,r);
    
    int i=l;
    for(int j=mid+1;j<=r;j++)
    {
        while(i<=mid&&q0[i].t<=q0[j].t)
        {
            if(q0[i].op==0) 
            {
                if(q0[i].x<0) 
                {
                    it=mp[q0[i].r].find(node3(q0[i].t-q0[i].l,-q0[i].x));
                    if(it!=mp[q0[i].r].end()) mp[q0[i].r].erase(it);
                }
                else
                    mp[q0[i].r].insert(node3(q0[i].t,q0[i].x));
                
                if(mp[q0[i].r].size()) 
                    modify(1,1,n,q0[i].r,mp[q0[i].r].begin()->v);
                else
                    modify(1,1,n,q0[i].r,-1);
            }
            i++;
        }
        if(q0[j].op==1) ans[q0[j].id]=max(ans[q0[j].id],query(1,1,n,q0[j].l,q0[j].r));
    }
    while(i>l) 
    {
        --i;
        if(q0[i].op==0)
        {
            modify(1,1,n,q0[i].r,-1);
            mp[q0[i].r].clear();
        }
    }
    
    inplace_merge(q0+l,q0+mid+1,q0+r+1,[](const node2&a,const node2&b){return a.t<b.t;});
}
int main()
{
    n=rd(),m=rd();
    memset(h,-1,sizeof h);
    memset(v,-1,sizeof v);
    memset(ans,-1,sizeof ans);
    for(int i=1;i<n;i++) 
    {
        int u=rd(),v=rd(),c=rd();
        add(u,v,c),add(v,u,c);
    }
    
    for(int i=1;i<=m;i++)
    {
        q[i].op=rd();
        q[i].u=rd();
        if(q[i].op) 
        {
            q[i].l=rd(),q[i].r=rd(),q[i].x=rd();
            V1[q[i].x].push_back(i);
        }
        else 
        {
            q[i].x=rd();
            V0[q[i].x].push_back(i);
        }
    }
    dis[1]=1;
    dfs(1,0);
    
    int cnt;
    for(int i=1;i<=n;i++)
    {
        if(V1[i].empty()) continue;
        cnt=0;
        for(int j=i;j<=n;j+=i)
        {
            for(int k:V0[j])
            {
                int u=q[k].u;
                q0[++cnt]={0,k,dfn[u],j,j,dis[u]};
                q0[++cnt]={0,k,dfn[u]+sz[u],sz[u],j,-dis[u]};
            }
        }
        for(int k:V1[i])
        {
            int u=q[k].u,l=q[k].l,r=q[k].r;
            q0[++cnt]={1,k,dfn[u],l,r};
        }
        
        sort(q0+1,q0+1+cnt,[](const node2& a,const node2 &b){return a.id<b.id||a.id==b.id&&a.t<b.t;});
        solve(1,cnt);
    }
    
    
    for(int i=1;i<=m;i++)
    {
        if(q[i].op==0) continue;
        if(ans[i]==-1)
            puts("Impossible!");
        else
            printf("%lld\n",dis[q[i].u]-ans[i]);
    }
}

调了一天了,现在感觉这样写不太行www,cdq分治必须贡献能够分开计算,显然最大值不能贡献累加,导致上面写法可能不太行,草(一种植物)一天没了~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值