zoukankan      html  css  js  c++  java
  • 题解-CF348E Pilgrims

    题面

    CF348E Pilgrims

    有一棵 (n) 个点的 带权 树和 (m) 个关键点,要求杀了一个不关键的点,满足最多的关键点到离它最远的所有关键点的路径都被打断。求可以满足的最多关键点数和此时的杀点方案数。

    数据范围:(2le m<nle 10^5)


    题解

    写了个奇怪的做法调了一个上午,写篇不行的题解。

    很明显所有关键点到所有离它最远的关键的所有路径都经过一个点:

    距离最远的一对关键点的中点(不需要取 (frac{dist}{2}) 的位置建出一个新点!如果真正的中心在边上,边上的两点都行!)。

    对于每个点 (u),如果以它为根,离它最远的所有点的 ( m lca)(v),只有杀 (u)(v) 路径上的点才能杀死 (u)

    所以目标就是对于每个 (u)(v),然后最后树上差分就可以了。

    可以以上文中的中点为根,边 dfs 边找,这个 (v) 是可以动态维护的。

    如果当前 dfs 到节点 (u),这个 (v) 绝不会是它的子树点,甚至不可能是和 (u) 在根的同一棵子树内的点。

    所以所有离 (u) 最远的点的当前 ( m lca) 就是 (v)

    可以线段树,维护区间最大值和最大值点的 ( m lca),支持区间加减。

    然后就解决了。如果嫌弃 (Theta(log n))pushup,可以用 ST(Theta(1)) lca


    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef double db;
    #define x first
    #define y second
    #define bg begin()
    #define ed end()
    #define pb push_back
    #define mp make_pair
    #define sz(a) int((a).size())
    #define R(i,n) for(int i(0);i<(n);++i)
    #define L(i,n) for(int i((n)-1);~i;--i)
    const int iinf=0x3f3f3f3f;
    const ll linf=0x3f3f3f3f3f3f3f3f;
    
    //Data
    const int N=1e5+1;
    int n,m,rt=-1,mon[N];
    bool imon[N],newed;
    
    //Tree_0
    const int D=20;
    vector<int> e[N],to,we;
    void adde(int u,int v,int w){
        e[u].pb(sz(to)),to.pb(v),we.pb(w);
        e[v].pb(sz(to)),to.pb(u),we.pb(w);
    }
    int dep[N],pre[N],in,dfn[N],lim[N],no[N];
    int in2,dfn2[N],lg[N<<1]; pair<int,int> st[D][N<<1];
    void dfs0(int u){
        for(int v:e[u])if(to[v]^to[pre[u]])
            dep[to[v]]=dep[u]+we[v],pre[to[v]]=v^1,dfs0(to[v]);
    }
    void dfs1(int u){
        no[dfn[u]=in++]=u,st[0][dfn2[u]=in2++]=mp(dep[u],u);
        for(int v:e[u])if(to[v]^pre[u])
            dep[to[v]]=dep[pre[to[v]]=u]+we[v],dfs1(to[v]),
                st[0][in2++]=mp(dep[u],u);
        lim[u]=in;
    }
    void linit(){
        R(i,D-1)R(u,in2-(2<<i)+1)
            st[i+1][u]=min(st[i][u],st[i][u+(1<<i)]);
        R(i,in2+1)if(i>1) lg[i]=lg[i>>1]+1;
    }
    int lca(int u,int v){
        u=dfn2[u],v=dfn2[v];
        if(u>v) swap(u,v); v++; int i=lg[v-u];
        return min(st[i][u],st[i][v-(1<<i)]).y;
    }
    
    //SegmentTree
    const int sN=N<<2;
    #define mid ((l+r)>>1)
    int mx[sN],tag[sN],anc[sN];
    void pushup(int u){
        if(mx[u*2+1]>mx[u*2+2]) mx[u]=mx[u*2+1],anc[u]=anc[u*2+1];
        else if(mx[u*2+2]>mx[u*2+1]) mx[u]=mx[u*2+2],anc[u]=anc[u*2+2];
        else mx[u]=mx[u*2+1],anc[u]=lca(anc[u*2+1],anc[u*2+2]);
    }
    void pushtag(int u,int v){tag[u]+=v,mx[u]+=v;}
    void pushdown(int u){tag[u]&&(pushtag(u*2+1,tag[u]),
        pushtag(u*2+2,tag[u]),tag[u]=0);}
    void sinit(int u=0,int l=0,int r=n){
        if(r-l==1) return mx[u]=imon[no[l]]?dep[no[l]]:-iinf,anc[u]=no[l],void();
        sinit(u*2+1,l,mid),sinit(u*2+2,mid,r),pushup(u);
    }
    void fixr(int x,int y,int v,int u=0,int l=0,int r=n){
        if(r<=x||y<=l) return; if(x<=l&&r<=y) return pushtag(u,v);
        pushdown(u),fixr(x,y,v,u*2+1,l,mid),fixr(x,y,v,u*2+2,mid,r),pushup(u);
    }
    void print(int u=0,int l=0,int r=n){
        if(r-l==1) return void(cout<<"["<<l<<"]:"<<mx[u]<<" ");
        pushdown(u),print(u*2+1,l,mid),print(u*2+2,mid,r);
    }
    #undef mid
    
    //Tree_1
    int mk[N];
    void dfs2(int u){
        if(imon[u]) mk[u]++,mk[anc[0]]++,mk[rt]--;
        for(int v:e[u])if(to[v]^pre[u]){
            fixr(0,n,we[v]),fixr(dfn[to[v]],lim[to[v]],-2*we[v]);
            dfs2(to[v]),fixr(0,n,-we[v]),fixr(dfn[to[v]],lim[to[v]],2*we[v]);
        }
    }
    void dfs3(int u){
        for(int v:e[u])if(to[v]^pre[u]) dfs3(to[v]),mk[u]+=mk[to[v]];
    }
    
    //Main
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0),cout.tie(0);
        cin>>n>>m;
        R(i,m) cin>>mon[i],--mon[i],imon[mon[i]]=true;
        R(i,n-1){int u,v,w; cin>>u>>v>>w,--u,--v,adde(u,v,w);}
        R(u,n) sort(e[u].bg,e[u].ed);
        int s=-1,t=-1,now=0;
        R(u,n) pre[u]=-1; dep[mon[0]]=0,dfs0(mon[0]);
        R(i,m)if(!~s||dep[mon[i]]>dep[s]) s=mon[i];
        R(u,n) pre[u]=-1; dep[s]=0,dfs0(s);
        R(i,m)if(!~t||dep[mon[i]]>dep[t]) t=mon[i];
        for(int u=t;u^s;u=to[pre[u]]){
            if(now>=dep[t]/2){rt=u;break;}
            now+=we[pre[u]];
        }
        if(!~rt) rt=s;
        R(u,n) pre[u]=-1;
        dep[rt]=0,dfs1(rt),linit(),sinit(),dfs2(rt),dfs3(rt);
        int mx=-1,cnt=0;
        R(u,n)if(!imon[u]){
            if(mk[u]>mx) mx=mk[u],cnt=1;
            else if(mk[u]==mx) cnt++; 
        }
        cout<<mx<<" "<<cnt<<'
    ';
        return 0;
    }
    

    祝大家学习愉快!

  • 相关阅读:
    Python驱动SAP GUI完成自动化(三)
    Python驱动SAP GUI完成自动化(选择布局+动态获取节点值)
    python中如何将货币数字转化成汉字大写金额
    python requests无法上传中文文件名的文件
    requests库结合selenium库共同完成web自动化和爬虫工作
    利用python第三方库提取PDF文件的表格内容
    pyinstaller打包exe文件闪退的解决办法
    pandas数据分析小知识点(一)
    java 终端输入小结,输入到数组、文件等(持续更新)
    Maven jenkins +Jmeter自动化测试
  • 原文地址:https://www.cnblogs.com/George1123/p/14035139.html
Copyright © 2011-2022 走看看