首页 > 其他分享 >CF-1399-E2-优先队列

CF-1399-E2-优先队列

时间:2024-01-22 13:35:30浏览次数:37  
标签:sz int CF dfs 队列 cost 1399 push E2

1399-E2 题目大意

给定一棵\(n\)个节点的树,边带权,根节点为\(1\)。再给定一个整数\(S\),你可以执行以下操作:

  • 选择一条权值为\(w_i\)的边,令\(w_i\rightarrow \lfloor \frac{w_i}{2} \rfloor\)。

你可以执行任意次操作,使得\(\sum_{x∈leaves}sum(1,x)\)不大于\(S\),其中\(sum(1,x)\)表示\(x\)到根节点的路径上的边权和。


Solution

一遍\(dfs\)求出各个边对答案的贡献,接下来依次执行操作,直到边权和小于等于\(S\)。

每次操作应当选取能够减少贡献最大的边,可以用优先队列来选取要操作的边。对于每个边在优先队列中的\(key\)应当是\((w_i-\lfloor \frac{w_i}{2} \rfloor)*cnt\),\(cnt\)为该边对答案的贡献次数。操作完后还需把边权减半重新加入优先队列中。

每个边最多经过\(logU\)次操作就会变为\(0\),这里的时间复杂度为\(O(nlognlogU)\)。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;

void solve(){
    int n;
    ll S;
    cin>>n>>S;
    vector<vector<pair<int,int>>> e(n);
    for(int i=1;i<n;i++){
        int x,y,w;
        cin>>x>>y>>w;
        --x,--y;
        e[x].push_back({y,w});
        e[y].push_back({x,w});
    }
    ll cost=0;
    vector<int> sz(n);
    priority_queue<tuple<ll,int,int>> q;
    function<void(int,int)> dfs=[&](int x,int fa){
        if(e[x].size()==1&&e[x][0].first==fa){
            sz[x]=1;
            return;
        }
        for(auto [y,w]:e[x]){
            if(y==fa) continue;
            dfs(y,x);
            sz[x]+=sz[y];
            cost+=1LL*w*sz[y];
            q.push({1LL*(w-w/2)*sz[y],w/2,sz[y]});
        }
    };
    dfs(0,-1);
    int ans=0;
    while(cost>S){
        auto [d,w,c]=q.top();
        q.pop();
        cost-=d;
        q.push({1LL*(w-w/2)*c,w/2,c});
        ans++;
    }
    cout<<ans<<'\n';
}

int main(){
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    int T=1;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

标签:sz,int,CF,dfs,队列,cost,1399,push,E2
From: https://www.cnblogs.com/fengxue-K/p/17979846

相关文章

  • CF1920D. Array Repetition
    思路用一个数组len记录每次操作后数组的长度,用一个数组lat记录每次操作后数组最后一个数字。对于每次询问,先二分查找出第几次操作能使数组的长度大于等于xac代码#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;consti64inf=1e18;typedefpair<in......
  • CF-461-B-树形DP
    461-B题目大意给定一棵\(n\)个节点的树,节点编号从\(0\)开始,每个节点要么为白色要么为黑色,你需要删除一些边,使得剩下的各个连通块中有且仅有一个黑色节点。问有多少种删边方案数,答案对\(10^9+1\)取模。Solution考虑树形DP,令\(dp[x][0/1]\)表示节点\(x\)属于无黑色节点/有黑色......
  • CF1920E 题解
    CF1920E被这种题卡了,脸都不要了。仔细读题,发现序列可以分成两部分(\(0\)和\(1\))来考虑。在合法序列中,对于一个\(1\),它产生的子串贡献一定是(假设与上一个\(1\)之间有\(x\)个\(0\),与下一个\(1\)之间有\(y\)个\(0\)):\[(x+1)(y+1)\]如果去DP这\(n\)个\(1\),易得转......
  • CF455D Serega and Fun 题解
    题目链接:CF或者洛谷本题是可以用平衡树去做的,具体的为每个\(k\)开一棵平衡树去维护相对位置,而这种移动操作用平衡树维护又是很容易做到的,这种做法是双\(log\)。在\(1e5\)的数据下,我们来说说好写的分块该如何去写。黑色的代表一个块,考虑暴力修改情况,假如原来的数字为\([1......
  • CF-570-D-启发式合并
    570-D题目大意给定一棵\(n\)个节点的树,根节点为\(1\),每个节点上有一个小写字母\(ch\)。定义节点\(x\)的深度为\(x\)到根节点的路径上的节点数量。\(q\)次询问,每次询问查询以\(x\)为根的子树之中所有深度为\(d\)的节点上字母重排之后是否可以构成一个回文串。Solution对于一组......
  • 从CF1901C学习除二向下取整的思路
    https://codeforces.com/problemset/problem/1901/C我发现对于向下取整向上取整的题目(特指除二),没有一些常见的思路积累。Description给定一个长度为\(n\)的序列\(\{a_n\}\)。每次操作你需要选择一个整数\(x\)并将所有\(a_i\)替换为\(\lfloor\frac{a_i+x}2\rfloo......
  • CF1375B Neighbor Grid 题解
    题意简述给你一个$n$行$m$列的矩阵,要求你让这个矩阵是“完美”的。“完美”的定义如下:若当前的格子里是一个正整数$k$,那么与这个网格相邻(有公共边)的$k$个格子也必须有一个正整数。若当前的格子里是$0$,那么不受上述的限制。你可以对任意的一个格子加上$1$,次数......
  • 对CF1904C的代码优化
    https://www.luogu.com.cn/problem/CF1904C分讨,然后\(k=2\)的时候肯定要写暴力,但是我的暴力很不优雅。石山voidsolve(){intn,k;cin>>n>>k;vector<ll>a(n+1);for(inti=1;i<=n;i++)cin>>a[i];if(k>=3){......
  • CF-915-F-并查集
    915-F题目大意给定一棵\(n\)个节点的树,节点带权,设函数\(I(x,y)\)等于点\(x\)到点\(y\)的路径上最大的点权与最小的点权之差。求:\[\sum_{i=1}^{n}\sum_{j=i}^{n}I(i,j)\]Solution令函数\(F(i,j)\)等于点\(x\)到点\(y\)的路径上最大的点权,函数\(G(i,j)\)等于点\(x\)到点\(y\)......
  • md2code code2md
    """convertcodetomarkdown"""importasyncioimportdatetimeimportosimportplatformimportreimportshutilimportxmlrpc.clientclassST:#<xxxxxxxxx>#<xxxxxxxxx>#<xxxxxxxxx>#&......