cf1260 F. Colored Tree

12 篇文章 0 订阅
10 篇文章 0 订阅

链接

点击跳转

AC的做法

枚举颜色,然后考虑我可以点亮某个点或者熄灭某个点,以点亮某个点为例,假设这个点是 i i i,枚举树上已经被点亮的点 j j j,那么此时答案的增量为
∑ j ( d e p t h i + d e p t h j − 2 d e p t h l c a ( i , j ) ) w i w j P \sum_{j} (depth_i+depth_j-2depth_{lca(i,j)})w_iw_jP j(depthi+depthj2depthlca(i,j))wiwjP

其中 P = ∏ ( r i − l i + 1 ) , w i = ( r i − l i + 1 ) − 1 P = \prod (r_i-l_i+1),w_i = (r_i-l_i+1)^{-1} P=(rili+1),wi=(rili+1)1

化简一下得到
P w i ( d e p t h i ∑ j d e p t h j + ∑ j w j d e p t h j − 2 ∑ j d e p t h l c a ( i , j ) w j ) P w_i \left( depth_i \sum_{j} depth_j + \sum_{j} w_j depth_j - 2 \sum_{j} depth_{lca(i,j)}w_j \right) Pwi(depthijdepthj+jwjdepthj2jdepthlca(i,j)wj)

一共三项,前两项都很容易维护

第三项,我可以对于已存在的 j j j,把根节点到 j j j的每个节点的权值都 + = w j +=w_j +=wj,那么 i i i到根节点这条路径上的权值之和就是第三项

AC的代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 100010
#define maxe 200010
#define cl(x) memset(x,0,sizeof(x))
#define rep(_,__) for(_=1;_<=(__);_++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
#define mod 1000000007ll
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
    ll c, f(1);
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-0x30;
    return f*x;
}
ll ans, n, l[maxn], r[maxn], inv[maxn], P, now, w[maxn];
struct SegmentTree
{
    ll sum[maxn<<2], add[maxn<<2], set[maxn<<2], L[maxn<<2], R[maxn<<2];
    void maketag_set(ll o, ll v)
    {
        add[o]=0;
        set[o]=v;
        sum[o]=(R[o]-L[o]+1)*v;
    }
    void maketag_add(ll o, ll v)
    {
        (add[o]+=v)%=mod;
        (sum[o]+=(R[o]-L[o]+1)*v)%=mod;
    }
    void pushdown(ll o)
    {
        if(L[o]==R[o])return;
        if(~set[o])
        {
            maketag_set(o<<1,set[o]);
            maketag_set(o<<1|1,set[o]);
            set[o]=-1;
        }
        if(add[o])
        {
            maketag_add(o<<1,add[o]);
            maketag_add(o<<1|1,add[o]);
            add[o]=0;
        }
    }
    void pushup(ll o)
    {
        (sum[o]=sum[o<<1]+sum[o<<1|1])%mod;
    }
    void build(ll o, ll l, ll r)
    {
        ll mid(l+r>>1);
        L[o]=l, R[o]=r;
        add[o]=0;
        set[o]=-1;
        if(l==r)
        {
            return;
        }
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
        pushup(o);
    }
    void segset(ll o, ll l, ll r, ll v)
    {
        ll mid(L[o]+R[o]>>1);
        if(l<=L[o] and r>=R[o]){maketag_set(o,v);return;}
        pushdown(o);
        if(l<=mid)segset(o<<1,l,r,v);
        if(r>mid)segset(o<<1|1,l,r,v);
        pushup(o);
    }
    void segadd(ll o, ll l, ll r, ll v)
    {
        ll mid(L[o]+R[o]>>1);
        if(l<=L[o] and r>=R[o]){maketag_add(o,v);return;}
        pushdown(o);
        if(l<=mid)segadd(o<<1,l,r,v);
        if(r>mid)segadd(o<<1|1,l,r,v);
        pushup(o);
    }
    ll segsum(ll o, ll l, ll r)
    {
        pushdown(o);
        ll mid(L[o]+R[o]>>1), ans(0);
        if(l<=L[o] and r>=R[o])return sum[o];
        if(l<=mid)ans+=segsum(o<<1,l,r);
        if(r>mid)ans+=segsum(o<<1|1,l,r);
        return ans%mod;
    }
}segtree;
struct Graph
{
    int etot, head[maxn], to[maxe], next[maxe], w[maxe];
    void clear(int N)
    {
        for(int i=1;i<=N;i++)head[i]=0;
        etot=0;
    }
    void adde(int a, int b, int c=0){to[++etot]=b;w[etot]=c;next[etot]=head[a];head[a]=etot;}
    #define forp(pos,G) for(auto p=G.head[pos];p;p=G.next[p])
}G;
struct Heavy_Light_Decomposition
{
    int size[maxn], top[maxn], tid[maxn], tim, untid[maxn], depth[maxn], son[maxn], fa[maxn];
    void dfs1(Graph &G, int pos)
    {
        int p, v;
        size[pos]=1;
        for(p=G.head[pos];p;p=G.next[p])
        {
            if((v=G.to[p])==fa[pos])continue;
            fa[v]=pos;
            depth[v]=depth[pos]+1;
            dfs1(G,v);
            if(size[v]>size[son[pos]])son[pos]=v;
            size[pos]+=size[v];
        }
    }
    void dfs2(Graph &G, int pos, int tp)
    {
        int p, v;
        top[pos]=tp;
        tid[pos]=++tim;
        untid[tid[pos]]=pos;
        if(son[pos])dfs2(G,son[pos],tp);
        for(p=G.head[pos];p;p=G.next[p])
            if((v=G.to[p])!=fa[pos] and v!=son[pos])dfs2(G,v,v);
    }
    void run(Graph &G, int root)
    {
        tim=0;
        depth[root]=1;
        dfs1(G,root);
        dfs2(G,root,root);
    }
}HLD;
vector<pll> events[maxn];
int main()
{
    ll n, i;
    inv[1]=1;
    for(int i=2;i<maxn;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod;
    n=read();
    P=1;
    rep(i,n)
    {
        l[i]=read(), r[i]=read();
        (P*=r[i]-l[i]+1)%=mod;
        w[i]=inv[r[i]-l[i]+1];
        events[l[i]].emb( pll(i,+1) );
        events[r[i]+1].emb( pll(i,-1) );
    }
    rep(i,n-1)
    {
        int u=read(), v=read();
        G.adde(u,v), G.adde(v,u);
    }
    HLD.run(G,1);
    segtree.build(1,1,n);
    ll sw=0, sdw=0;
    rep(i,1e5)
    {
        for(auto e:events[i])
        {
            auto pos=e.fi, v=e.se;
            ll delt=0;
            (delt += HLD.depth[pos]*sw)%=mod;
            (delt += sdw)%=mod;
            ll s=0, x=pos;
            while(x)
            {
                auto tp = HLD.top[x];
                (s+=segtree.segsum(1,HLD.tid[tp],HLD.tid[x]))%=mod;
                x=HLD.fa[tp];
            }
            (delt -= 2*s)%=mod;
            (now+=v*P*w[pos]%mod*delt)%=mod;
            x=pos;
            while(x)
            {
                auto tp = HLD.top[x];
                segtree.segadd(1,HLD.tid[tp],HLD.tid[x],w[pos]*v);
                x=HLD.fa[tp];
            }
            (sw+=v*w[pos])%=mod;
            (sdw+=v*w[pos]*HLD.depth[pos])%=mod;
        }
        (ans+=now)%=mod;
    }
    cout<<(ans+mod)%mod;
    return 0;
}

因为常数太大而 T L E TLE TLE的做法

点分治,一棵子树一棵子树的进行合并

新来一棵子树的时候,我就对于每个节点都求一下它颜色区间的深度和,这是路径的一段,另一段可以通过维护每种颜色被多少个点包含了进而算出来

两个线段树可能常数比较大?
而且实际上线段树操作的调用次数也比前一种算法多,所以就 T L E TLE TLE

因为常数太大而 T L E TLE TLE的代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 100010
#define maxe 200010
#define maxk 17
#define cl(x) memset(x,0,sizeof(x))
#define rep(_,__) for(_=1;_<=(__);_++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
#define mod 1000000007ll
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
    ll c, f(1);
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-0x30;
    return f*x;
}
ll ans, n, l[maxn], r[maxn], inv[maxn], P;
struct SegmentTree
{
    ll sum[maxn<<2], add[maxn<<2], set[maxn<<2], L[maxn<<2], R[maxn<<2];
    void maketag_set(ll o, ll v)
    {
        add[o]=0;
        set[o]=v;
        sum[o]=(R[o]-L[o]+1)*v;
    }
    void maketag_add(ll o, ll v)
    {
        (add[o]+=v)%=mod;
        (sum[o]+=(R[o]-L[o]+1)*v)%=mod;
    }
    void pushdown(ll o)
    {
        if(L[o]==R[o])return;
        if(~set[o])
        {
            maketag_set(o<<1,set[o]);
            maketag_set(o<<1|1,set[o]);
            set[o]=-1;
        }
        if(add[o])
        {
            maketag_add(o<<1,add[o]);
            maketag_add(o<<1|1,add[o]);
            add[o]=0;
        }
    }
    void pushup(ll o)
    {
        (sum[o]=sum[o<<1]+sum[o<<1|1])%mod;
    }
    void build(ll o, ll l, ll r)
    {
        ll mid(l+r>>1);
        L[o]=l, R[o]=r;
        add[o]=0;
        set[o]=-1;
        if(l==r)
        {
            return;
        }
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
        pushup(o);
    }
    void segset(ll o, ll l, ll r, ll v)
    {
        ll mid(L[o]+R[o]>>1);
        if(l<=L[o] and r>=R[o]){maketag_set(o,v);return;}
        pushdown(o);
        if(l<=mid)segset(o<<1,l,r,v);
        if(r>mid)segset(o<<1|1,l,r,v);
        pushup(o);
    }
    void segadd(ll o, ll l, ll r, ll v)
    {
        ll mid(L[o]+R[o]>>1);
        if(l<=L[o] and r>=R[o]){maketag_add(o,v);return;}
        pushdown(o);
        if(l<=mid)segadd(o<<1,l,r,v);
        if(r>mid)segadd(o<<1|1,l,r,v);
        pushup(o);
    }
    ll segsum(ll o, ll l, ll r)
    {
        pushdown(o);
        ll mid(L[o]+R[o]>>1), ans(0);
        if(l<=L[o] and r>=R[o])return sum[o];
        if(l<=mid)ans+=segsum(o<<1,l,r);
        if(r>mid)ans+=segsum(o<<1|1,l,r);
        return ans%mod;
    }
}sum_tree, cnt_tree;
struct Graph
{
    int etot, head[maxn], to[maxe], next[maxe], w[maxe];
    void clear(int N)
    {
        for(int i=1;i<=N;i++)head[i]=0;
        etot=0;
    }
    void adde(int a, int b, int c=0){to[++etot]=b;w[etot]=c;next[etot]=head[a];head[a]=etot;}
    #define forp(pos,G) for(auto p=G.head[pos];p;p=G.next[p])
}G;
struct Centroid_Decomposition
{
    ll grey[maxn], depth[maxn], size[maxn], dist[maxn], lis[maxn];
    void dfs(ll pos, ll pre, Graph& G)
    {
        lis[++*lis]=pos;
        // lis.emb(pos);
        // de(pos);
        size[pos]=1;
        forp(pos,G)if(G.to[p]!=pre and !grey[G.to[p]])
        {
            depth[G.to[p]]=depth[pos]+1;
            dist[G.to[p]]=dist[pos]+G.w[p];
            dfs(G.to[p],pos,G);
            size[pos]+=size[G.to[p]];
        }
    }
    void findG(ll pos, ll pre, Graph& G, ll& g, ll& gsum, ll nowsum, ll node_tot)
    {
        if(nowsum<gsum)g=pos, gsum=nowsum;
        forp(pos,G)if(G.to[p]!=pre and !grey[G.to[p]])
            findG( G.to[p], pos, G, g, gsum, nowsum+(node_tot-2*size[G.to[p]]), node_tot );
    }
    void solve(ll pos, Graph& G)
    {
        *lis=0; dfs(pos,0,G);
        ll g=pos, gsum=0, i;
        rep(i,*lis)gsum+=depth[lis[i]];//, cerr<<x<<'('<<size[x]<<')'<<' ';cerr<<endl;
        findG(pos,0,G,g,gsum,gsum,*lis);
        grey[g]=1;
        //--- process ---
        sum_tree.segset(1,1,1e5,0);
        cnt_tree.segset(1,1,1e5,0);
        forp(g,G)if(!grey[G.to[p]])
        {
            depth[G.to[p]]=1;
            *lis=0;dfs(G.to[p],g,G);
            rep(i,*lis)
            {
                auto x=lis[i];
                ans += sum_tree.segsum(1,l[x],r[x])*inv[r[x]-l[x]+1]%mod;
                ans += cnt_tree.segsum(1,l[x],r[x])*depth[x]%mod*inv[r[x]-l[x]+1]%mod;
                ans%=mod;
            }
            rep(i,*lis)
            {
                auto x=lis[i];
                sum_tree.segadd(1,l[x],r[x],depth[x]*inv[r[x]-l[x]+1]%mod*P%mod);
                cnt_tree.segadd(1,l[x],r[x],inv[r[x]-l[x]+1]*P%mod);
            }
        }
        (ans+=sum_tree.segsum(1,l[g],r[g])*inv[r[g]-l[g]+1])%=mod;   //不要忘记处理一端在重心的路径
        //---------------
        forp(g,G)if(!grey[G.to[p]])solve(G.to[p],G);
    }
}CD;
int main()
{
    int n, i;
    inv[1]=1;
    for(int i=2;i<maxn;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod;
    n=read();
    P=1;
    rep(i,n)
    {
        l[i]=read(), r[i]=read();
        (P*=r[i]-l[i]+1)%=mod;
    }
    rep(i,n-1)
    {
        int u=read(), v=read();
        G.adde(u,v), G.adde(v,u);
    }
    // de("debug1");
    sum_tree.build(1,1,1e5);
    cnt_tree.build(1,1,1e5);
    // de("debug2");
    CD.solve(1,G);
    cout<<ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值