UOJ #276. 【清华集训2016】汽水

TMD写了一篇博客竟然还不够清醒,那就再写一篇睡觉去了

首先一看题目就会发现这可以先套上个分数规划,即我们现在要最小化\(|\frac{\sum_{i=1}^{len} w_i}{len}-k|\)

考虑二分答案\(x\),顺便拆掉绝对值,即\(-x\le\frac{\sum_{i=1}^{len} w_i}{len}-k\le x\),发现其实只要同时满足:

\[\sum_{i=1}^{len} w_i-k+x \ge 0\]

\[\sum_{i=1}^{len} w_i-k-x \le 0\]

所以\(k\)不用管直接减掉即可,考虑就是找一条路径同时满足上述两个条件

然后又考虑到这是树上问题,我们考虑点分治,如果单看第一个条件很简单,只要把分治中心到所有点的边权和搞出来,找两条(或一条)长度大于\(0\)的即可

那么还有第二个要求怎么办,不难发现因为只用取两条链,因此我们可以在满足第一个的情况下最小化第二个的值,这个可以排序后two points扫一下解决

注意一下两条链都在同一子树内的情况要判一下,总体复杂度\(O(n\log^2 n)\)

#include<cstdio>
#include<iostream>
#include<algorithm>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
typedef long double DB;
const int N=100005,INF=1e18;
const DB EPS=1e-3;
struct edge
{
    int to,nxt; DB v1,v2;
}e[N<<1]; int n,head[N],cnt,k,x,y,z;
inline void addedge(CI x,CI y,CI z)
{
    e[++cnt]=(edge){y,head[x],(DB)z-k,(DB)z-k}; head[x]=cnt;
    e[++cnt]=(edge){x,head[y],(DB)z-k,(DB)z-k}; head[y]=cnt;
}
class Point_Division_Solver
{
    private:
        struct data
        {
            int id; DB d1,d2;
            friend inline bool operator < (const data& A,const data& B)
            {
                return A.d1<B.d1;
            }
        }d[N]; int size[N],mx[N],ots,tot,rt; bool vis[N];
        #define to e[i].to
        inline void getrt(CI now,CI fa=0)
        {
            size[now]=1; mx[now]=0; for (RI i=head[now];i;i=e[i].nxt) if (to!=fa&&!vis[to])
            getrt(to,now),size[now]+=size[to],mx[now]=max(mx[now],size[to]);
            if ((mx[now]=max(mx[now],ots-size[now]))<mx[rt]) rt=now;
        }
        inline void travel(CI now,CI fr,CI fa,const DB& dis1,const DB& dis2)
        {
            d[++tot]=(data){fr,dis1,dis2}; for (RI i=head[now];i;i=e[i].nxt)
            if (to!=fa&&!vis[to]) travel(to,fr,now,dis1+e[i].v1,dis2+e[i].v2);
        }
        inline void insert(int& mi,int& smi,CI p)
        {
            if (d[p].d2<d[mi].d2) { if (d[p].id!=d[mi].id) smi=mi; mi=p; }
            else if (d[p].d2<d[smi].d2&&d[p].id!=d[mi].id) smi=p;
        }
        inline bool judge(CI rt)
        {
            RI i,pos,mi,smi; for (d[tot=1]=(data){rt,0,0},i=head[rt];i;i=e[i].nxt)
            if (!vis[to]) travel(to,to,rt,e[i].v1,e[i].v2);
            sort(d+1,d+tot+1); d[0].d2=INF; for (i=pos=1;d[i].d1<0;++i,++pos);
            for (mi=smi=0;i<=tot;++i)
            {
                while (pos>1&&d[pos-1].d1+d[i].d1>=0) insert(mi,smi,--pos);
                if (d[mi].id!=d[i].id&&d[mi].d2+d[i].d2<=0) return 1;
                if (d[mi].id==d[i].id&&d[smi].d2+d[i].d2<=0) return 1;
                insert(mi,smi,i);
            }
            return 0;
        }
        inline bool solve(CI now)
        {
            vis[now]=1; if (judge(now)) return 1;
            for (RI i=head[now];i;i=e[i].nxt) if (!vis[to])
            {
                mx[rt=0]=INF; ots=size[to]; getrt(to);
                if (solve(rt)) return 1;
            }
            return 0;
        }
        #undef to
    public:
        inline bool check(const DB& x)
        {
            //printf("%lld : ",(int)x);
            RI i; for (i=1;i<=n;++i) vis[i]=0;
            for (i=1;i<=cnt;++i) e[i].v1+=x,e[i].v2-=x;
            mx[rt=0]=INF; ots=n; getrt(1); bool flag=solve(rt);
            for (i=1;i<=cnt;++i) e[i].v1-=x,e[i].v2+=x; return flag;
        }
}PD;
signed main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    RI i; for (scanf("%lld%lld",&n,&k),i=1;i<n;++i)
    scanf("%lld%lld%lld",&x,&y,&z),addedge(x,y,z);
    DB l=0,r=1e13,mid; while (r-l>EPS)
    if (PD.check(mid=(l+r)/2.0)) r=mid; else l=mid;
    return printf("%lld",(int)(r)),0;
}

原文地址:https://www.cnblogs.com/cjjsb/p/11616519.html

时间: 2024-08-01 20:56:13

UOJ #276. 【清华集训2016】汽水的相关文章

UOJ276 [清华集训2016] 汽水 【二分答案】【点分治】【树状数组】

题目分析: 这种乱七八糟的题目一看就是点分治,答案有单调性,所以还可以二分答案. 我们每次二分的时候考虑答案会不会大于等于某个值,注意到系数$k$是无意义的,因为我们可以通过转化使得$k=0$. 合并的过程相当于很多个向量,加起来后看斜率. 注意单个向量也要判定. 由于有了二分的答案$Ans$.判定变得简单多了,推一下. $-k \leq \frac{A+C}{B+D} \leq k \Rightarrow -k(B+D) \leq A+C \leq k(B+D)$. 进一步的$A+kB \ge

【UOJ274】【清华集训2016】温暖会指引我们前行 LCT

[UOJ274][清华集训2016]温暖会指引我们前行 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的宿舍楼中有n个地点和一些路,一条路连接了两个地点,小R可以通过这条路从其中任意一个地点到达另外一个地点.但在刚开始,小R还不熟悉宿舍楼中的任何一条路,所以他会慢慢地发现这些路,他在发现一条路时还会知道这条路的温度和长度.每条路的温度都是互不相同的. 小R需要在宿舍楼中活动,每次他都需要从

bzoj 4736 /uoj274【清华集训2016】温暖会指引我们前行 lct

[清华集训2016]温暖会指引我们前行 统计 描述 提交 自定义测试 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一位火焰之神 “我将赐予你们温暖和希望!” 只见他的身体中喷射出火焰之力 通过坚固的钢铁,传遍了千家万户 这时,只听见人们欢呼 “暖气来啦!” 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的

【UOJ】#273. 【清华集训2016】你的生命已如风中残烛

题目链接:http://uoj.ac/problem/273 $${Ans=\frac{\prod _{i=1}^{m}i}{w-n+1}}$$ 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8

UOJ 274 【清华集训2016】温暖会指引我们前行 ——Link-Cut Tree

魔法森林高清重置, 只需要维护关于t的最大生成树,然后链上边权求和即可. 直接上LCT 调了将近2h 吃枣药丸 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i&g

uoj#268. 【清华集训2016】数据交互(动态dp+堆)

传送门 动态dp我好像还真没咋做过--通过一个上午的努力光荣的获得了所有AC的人里面的倒数rk3 首先有一个我一点也不觉得显然的定理,如果两条路径相交,那么一定有一条路径的\(LCA\)在另一条路径上 于是我们可以对于每一个点记录两个值,一个\(a_i\)表示\(LCA\)在\(i\)点的所有路径的权值之和,一个是\(b_i\),表示经过点\(i\)且\(LCA\)不在点\(i\)的所有路径的权值之和 那么对于一条路径\((u,v)\),它的权值就是\(b_{LCA(u,v)}+\sum_{i\

uoj#269. 【清华集训2016】如何优雅地求和(数论)

传送门 首先,如果\(f(x)=1\),那么根据二项式定理,有\(Q(f,n,k)=1\) 当\(f(x)=x\)的时候,有\[Q=\sum_{i=0}^ni\times \frac{n!}{i!(n-i)!}k^i(1-k)^{n-i}\] \[Q=\sum_{i=0}^nnk\times \frac{(n-1)!}{(i-1)!(n-i)!}k^{i-1}(1-k)^{n-i}\] \[Q=nk\sum_{i=0}^n\frac{(n-1)!}{(i-1)!(n-i)!}k^{i-1}(1-

uoj#273. 【清华集训2016】你的生命已如风中残烛(组合数学)

传送门 一道打表题 我们把那些普通牌的位置看成\(-1\),那么就是要求有多少个排列满足前缀和大于等于\(1\) 考虑在最后放一个\(-1\),那么就是除了\(m+1\)的位置前缀和都要大于等于\(1\) \(m+1\)个数的圆排列的方案数为\(m!\),然后对于每一个圆排列,肯定存在一个前缀和最小且最右边的位置,那么它后面的所有位置肯定前缀和都大于等于\(1\),而对于这个位置如果不把它放最后肯定会有前缀和小于\(1\) 所以对于每一种圆排列有且仅有一种摆放方式合法 然而此时最后的这个\(-1

UOJ#272. 【清华集训2016】石家庄的工人阶级队伍比较坚强

传送门 设运算 \(op1,op2\),一个表示三进制不进位的加法,一个表示不退位的减法 设 \(cnt1[x],cnt2[x]\) 分别表示 \(x\) 转成三进制后 \(1/2\) 的个数 那么 \(f_{i,x}=\sum f_{i-1,y}b_{cnt1[x~op2~y],cnt2[x~op2~y]}\) 设 \(B_{x,y}=b_{cnt1[x~op2~y],cnt2[x~op2~y]}\) 那么可以发现 \(B_{x,y}=B_{x~op2~y,0}\) 那么我们要求的就是 \(f