首页 > 其他分享 >题解 CF1787G【Colorful Tree Again】

题解 CF1787G【Colorful Tree Again】

时间:2023-09-08 15:47:14浏览次数:38  
标签:颜色 int 题解 top CF1787G sumw Tree include deg

problem

贼眉鼠眼有一棵 \(N\) 个节点的树,这棵树很特殊,每条边都有边权和颜色。

果宝特攻会不定时来进攻贼眉鼠眼。具体地,在前 \(Q\) 个时刻,在每个时刻,会发生以下两个事件之一:

  1. 果宝特攻摧毁了树上的一个节点 \(u\)。

  2. 贼眉鼠眼修复了树上的一个节点 \(u\)。

定义一条简单路径指图中没有重复节点的路径。简单路径的长度定义为路径上所有边的边权之和。

定义这棵树的能量值为以下满足条件的简单路径的长度的最大值:该简单路径的边颜色均为 \(c\),且该简单路径包含所有颜色为 \(c\) 的边。

贼眉鼠眼想知道对于每个时刻,它的树的能量值为多少,以抵御果宝特攻的进攻。

100% 的数据:\(N,Q\le2×10^5,w_i\le 10^9,u_i,v_i,c_i\le N\)。

solution

就是将每种颜色的边拎出来,如果对于一种颜色它不是链则丢掉,否则只有当链上的点全部存活它才能有贡献。

将边与边用并查集合并可以得到一个 \(O(\deg)\) 的插入,不支持删除,所以线段树分治。那就更加糟糕了,没有前途。

考虑在树上搞这个东西,将一个点 \(u\) 的边分成向上的和经过自己的。可以对颜色定义 \(top_c\) 表示深度最浅的点,然后将这个颜色挂在 \(top_c\) 上。修改 \(u\) 的时候,将 \(top_c=u\) 的封掉,将自己上去的颜色封掉,可以用线段树维护颜色(区间加,全局最大值)。

code

点击查看代码
#include <cstdio>
#include <vector>
#include <cstring>
#include <tuple>
#include <numeric>
#include <cassert>
#include <algorithm>
#include <functional>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr,##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
template<int N> struct segtree{
    pair<int,LL> ans[N<<2]; int tag[N<<2];
    void maintain(int p){ans[p]=max(ans[p<<1],ans[p<<1|1]);}
    void spread(int p,int k){ans[p].first+=k,tag[p]+=k;}
    void pushdown(int p){if(tag[p]) spread(p<<1,tag[p]),spread(p<<1|1,tag[p]),tag[p]=0;}
    void build(function<LL(int)> w,int p,int l,int r){
        tag[p]=0;
        if(l==r) return ans[p]={0,w(l)},void();
        int mid=(l+r)>>1;
        build(w,p<<1,l,mid);
        build(w,p<<1|1,mid+1,r);
        maintain(p);
    }
    void modify(int L,int R,int k,int p,int l,int r){
        if(L>R) return ;
        if(L<=l&&r<=R) return spread(p,k);
        int mid=(l+r)>>1; pushdown(p);
        if(L<=mid) modify(L,R,k,p<<1,l,mid);
        if(mid<R) modify(L,R,k,p<<1|1,mid+1,r);
        maintain(p);
    }
};
template<int N,int M> struct graph{
    int head[N+10],nxt[M<<1],cnt;
    struct edge{int u,v,w,c;} e[M<<1];
    graph():cnt(0){memset(head,0,sizeof head);}
    edge&operator[](int i){return e[i];}
    int add(int u,int v,int w,int c){
        e[++cnt]={u,v,w,c},nxt[cnt]=head[u];
        return head[u]=cnt;
    }
};
int n,m,deg[1<<18],top[1<<18],dep[1<<18];
LL sumw[1<<18];//for color
vector<int> buc[1<<18],pcs[1<<18];
graph<1<<18,1<<18> g;
segtree<1<<18> t;
void getsumw(){
    dep[0]=1e9;
    for(int c=1;c<=n;c++){
        int cnt[3]={0,0,0};
        LL tot=0;
        for(auto i:buc[c]){
            tot+=g[i].w;
            for(int u:{g[i].u,g[i].v}){
                if(deg[u]>=2){sumw[c]=-1; continue;}
                cnt[deg[u]]--,cnt[++deg[u]]++;
                if(dep[top[c]]>dep[u]) top[c]=u;
            }
        }
        if(cnt[1]!=2) sumw[c]=-1;
        if(sumw[c]!=-1) sumw[c]=tot,pcs[top[c]].push_back(c),debug("sumw[%d]=%d,top=%d\n",c,sumw[c],top[c]);
        for(auto i:buc[c]) deg[g[i].u]=deg[g[i].v]=0;
    }
}
int upc[1<<18];
void dfs(int u,int f){
    dep[u]=dep[f]+1;
    for(int i=g.head[u];i;i=g.nxt[i]){
        int v=g[i].v; if(v==f) continue;
        dfs(v,u),upc[v]=g[i].c;
    }
}
int Lpos[1<<18],dfn[1<<18],rnk[1<<18],dfncnt,Q;
int main(){
//  #ifdef LOCAL
//      freopen("input.in","r",stdin);
//  #endif
    scanf("%d%d",&n,&Q);
    for(int i=1,u,v,w,c;i<n;i++){
        scanf("%d%d%d%d",&u,&v,&w,&c);
        g.add(u,v,w,c),g.add(v,u,w,c);
        buc[c].push_back(g.cnt);
    }
    dfs(1,0),getsumw();
    for(int i=1;i<=n;i++){
        Lpos[i]=m+1;
        for(int c:pcs[i]) rnk[dfn[c]=++m]=c;
    }
    if(!m){
        for(int i=1;i<=Q;i++) puts("0");
        return 0;
    }
    t.build([&](int i){return sumw[rnk[i]];},1,1,m);
    for(int op,u;Q--;){
        scanf("%d%d",&op,&u);
        op=(op==1?-1:1);
        if(pcs[u].size()) t.modify(Lpos[u],Lpos[u]+pcs[u].size()-1,op,1,1,m);
        if(dfn[upc[u]]) t.modify(dfn[upc[u]],dfn[upc[u]],op,1,1,m);
        pair<int,LL> res=t.ans[1];
        if(res.first<0||res.second<0) puts("0");
        else printf("%lld\n",res.second);
    }
    return 0;
}

标签:颜色,int,题解,top,CF1787G,sumw,Tree,include,deg
From: https://www.cnblogs.com/caijianhong/p/solution-CF1787G.html

相关文章

  • 国标GB28181视频监控EasyGBS接入大量通道时,创建角色接口未响应的问题解决方法
    EasyGBS是一款基于国标GB28181协议的视频云服务平台。它支持多路设备同时接入,并能将视频流以RTSP、RTMP、FLV、HLS、WebRTC等格式分发到多个平台和终端。该平台提供了视频监控直播、云端录像、云存储、检索回放、智能告警、语音对讲、平台级联等功能。在视频能力方面,GB28181视频监......
  • CF868E Policeman and a Tree 题解
    Description.树上警察抓小偷。一名警察速度为\(1\),多名小偷速度为\(+\infty\),问多长时间抓到。树点数\(\le50\)Solution.首先不可能抓不到。其次步数不可能超过\(2500\)(每抓完一个小偷走一遍全图)。这启发我们可以直接暴搜每一步,并记忆化。如果状态设为当前在\(x\),那......
  • elementui tree 获取选中子节点的所有父级节点信息
    //获取选中的节点constcheckedNodes=this.$refs.rolePermissionsTree.getCheckedNodes(false,true)//获取选中节点的所有父级节点checkedNodes.forEach(node=>{console.log(node)})效果如下......
  • 【题解】《PTA-Python程序设计》题目集分享
    第1章-1从键盘输入两个数,求它们的和并输出(30分)本题目要求读入2个整数A和B,然后输出它们的和。输入格式:在一行中给出一个被加数在另一行中给出一个加数输出格式:在一行中输出和值。输入样例:在这里给出一组输入。例如:18-48输出样例:在这里给出相应的输出。例如:......
  • 题解 P8165 [eJOI2021] AddK
    不知道为什么这道题还没有题解。Solution对于操作\(1\),由于\(K\le10\),直接暴力单点修改即可。而操作\(2\)的询问,不难发现,最后结果的呈现形式是\[1\timesA_l+2\timesA_{l+1}+3\timesA_{l+2}+...+3\timesA_{r-2}+2\timesA_{r-1}+1\timesA_r\]其中中间可能有一段系数......
  • [element-ui] el-tree 懒加载load
    懒加载:点击节点时才进行该层数据的获取。注意:使用了懒加载之后,一般情况下就可以不用绑定:data。<el-tree:props="props":load="loadNode"lazy></el-tree>懒加载—由于在点击节点时才进行该层数据的获取,默认情况下Tree无法预知某个节点是否为叶子节点,所以会为每个节点添加一个......
  • SP8177 题解
    2023-09-0111:29:13solution题意:每次询问\([l,r]\)内有多少个数满足可以被所有非\(0\)数位整除。思路看到这个数据范围和题目描述,显然是数位dp。因为\(1\sim9\)的最小公倍数是\(2520\),并且\(2520\)是其他所有\(1\sim9\)子集的最小公倍数的倍数,所以我们只需要......
  • CF402D 题解
    2023-09-0418:42:46solution不难想到我们要先记录一下每一位的前缀\(\gcd\),我们发现我们选择一位的前缀\(\gcd\)除掉以后,前缀\(\gcd\)会变为\(1\)并且会导致这位之后的\(\gcd\)全部为\(1\)。所以每一位只能选择一次,并且我们从后往前扫肯定比从前往后扫要更优。我们......
  • wzOI 2023.8.31 题解
    2023-09-0115:59:41$$前言$$太菜了,第一题都打成那样了没发现是MST,第三题数据范围没有很仔细看,以为是乱搞(组合之类的)题就直接跳了。不得不说这次比赛题目的一些思路还是挺妙的,一些想法确实我这种成分想不太到。$$A$$$$题意$$给出了\(m\)个可以查询的区间\([L_i,R_i]\)......
  • CF1103C 题解
    2023-09-0514:52:07solution找路径很好找,我们随便跑个dfs树找个深度\(\ge\frac{n}{k}\)的路径输出即可。可是怎么找\(k\)个长度不是\(3\)的倍数的环呢?既然我们跑了dfs树,那么就没有横叉边,对于叶子节点非树边只有返祖边,然后一看这个很奇怪的条件——保证每个点度数大......