并不对劲的uoj276. [清华集训2016]汽水
题目大意
有一棵\(n\)(\(n\leq 50000\))个节点的树,有边权
求一条路径使该路径的边权平均值最接近给出的一个数\(k\)
输出边权平均值下取整的整数部分
题解
有关路径的边权平均值可以二分来做
假设已二分出边权平均值与\(k\)的差不超过\(m\),则应存在一条简单路径,路径上的\(p\)条边满足:
\]
两边同乘\(p\),得:
\]
也就是$$\begin{cases}{\sum_{i=1}^{p}{(w_i-k+m)}}\geq 0\\sum_{i=1}^{p}{(w_i-k-m)}\leq 0\end{cases}$$
那么设\(a_i=w_i-k+m,b_i=w_i-k-m\),问题就变成了判断图中是否存在一条简单路径,满足\(\Sigma a_i\geq 0\)且\(\Sigma b_i\leq 0\)
这种在树上找满足某个条件的链的问题可以用点分治解决
设某点\(i\)到当前区域的重心的简单路径上,\(a_k\)之和为\(A_i\),\(b_k\)之和为\(B_i\)
则问题转化为找两点\(i\),\(j\)不属于当前区域的重心的同一子树,且\(A_i+A_j\geq0\),\(B_i+B_j\leq0\)
也可以看成是对于点\(i\),所有\(A_j\geq-A_i\)的点\(j\)中,\(B_j\)的最小值是否小于\(-B_i\)
这个可以用平衡树或权值线段树来维护
再算上二分、点分治的时间复杂度,总时间复杂度使\(\Theta(n\space log^3 n)\)的,看上去有点悬
考虑加一些小优化,比如:
1.预处理点分树,就不用二分时每次判断都求一遍重心;
2.当找到一条合法的链后,立刻退出;
3.没有必要把当前区域的重心的最后一个儿子的子树里的点的信息加入平衡树或权值线段树
...
然而还是跑得很慢…
#include<algorithm>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define maxn 50010
#define maxm (maxn<<1)
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define ls son[u][0]
#define rs son[u][1]
#define eps 5e-3
#define LD long double
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
const double inf=(1.0/0.0);
double mx[maxn],key[maxn],key2[maxn],dep[maxn],dep2[maxn],w[maxm],K,L,R,mid,ans;
int n,fa[maxn],son[maxn][2],rt,vis[maxn],ww[maxn],siz[maxn],nowsiz,mnsiz,wt,nxt[maxm],fir[maxn],v[maxm],cnt,nd,yes;
int nt[maxn],vv[maxn],fs[maxn],cnt2,root;
void ade(int u1,int v1,double w1){v[cnt]=v1,nxt[cnt]=fir[u1],w[cnt]=w1,fir[u1]=cnt++;}
void ade2(int u1,int v1){vv[cnt2]=v1,nt[cnt2]=fs[u1],fs[u1]=cnt2++;}
void getsiz(int u,int fa)
{
siz[u]=1;int nowmx=0;
for(int k=fir[u];k!=-1;k=nxt[k])
if(v[k]!=fa&&!vis[v[k]])getsiz(v[k],u),siz[u]+=siz[v[k]],nowmx=max(nowmx,siz[v[k]]);
nowmx=max(nowmx,nowsiz-siz[u]);
if(nowmx<mnsiz)mnsiz=nowmx,wt=u;
}
void getwt(int u,int fa,int sumsiz)
{
nowsiz=sumsiz,mnsiz=n+1,getsiz(u,0),vis[wt]=1;
int now=wt;
if(sumsiz==n)root=now;
else ade2(fa,now);
for(int k=fir[now];k!=-1;k=nxt[k])
if(!vis[v[k]])getwt(v[k],now,siz[v[k]]>siz[now]?sumsiz-siz[now]:siz[v[k]]);
}
void pu(int u)
{
if(!u)return;
mx[u]=key2[u];
if(ls)mx[u]=min(mx[u],mx[ls]);
if(rs)mx[u]=min(mx[u],mx[rs]);
return;
}
int getso(int u){return son[fa[u]][0]!=u;}
void rot(int u)
{
register int fu=fa[u],ffu=fa[fu],l=getso(u),fl=getso(fu),r=l^1,rson=son[u][r];
if(ffu)son[ffu][fl]=u;son[u][r]=fu,son[fu][l]=rson;if(rson)fa[rson]=fu;fa[u]=ffu,fa[fu]=u;
pu(fu),pu(u);
}
void ins(double x,double y)
{
register int u=rt,lst=0,to;
while(u&&key[u]!=x)lst=u,to=x>key[u]?1:0,u=son[u][to];
if(!u)
{
u=++nd,ls=rs=0,key[u]=x,key2[u]=y,mx[u]=y,ww[u]=rand()*rand()%63427919,fa[u]=lst;
if(lst)son[lst][to]=u/*,upd2(lst)*/;
else rt=u;
while(fa[u]&&ww[fa[u]]>ww[u])rot(u);
if(!fa[u])rt=u;
}
else {key2[u]=min(key2[u],y),mx[u]=min(mx[u],y);while(u)pu(u),u=fa[u];}return;
}
double ask(double x)
{
int u=rt;double res=inf;
while(u)
{
if(x<=key[u]){res=min(res,min(key2[u],rs?mx[rs]:inf));u=ls;}
else u=rs;
}
return res;
}
void asky(int u,int fa)
{
double res=ask(-dep[u]);
if(res!=inf){if(res+dep2[u]<=0){yes=1;return;}}
for(int k=fir[u];k!=-1;k=nxt[k])
if(!vis[v[k]]&&v[k]!=fa)
{
dep[v[k]]=dep[u]+w[k]+mid,dep2[v[k]]=dep2[u]+w[k]-mid,asky(v[k],u);
if(yes)return;
}
}
void addy(int u,int fa)
{
ins(dep[u],dep2[u]);
for(int k=fir[u];k!=-1;k=nxt[k])
if(!vis[v[k]]&&v[k]!=fa)addy(v[k],u);
}
void reset(){rt=0;nd=0,mx[0]=inf;}
void gety(int now)
{
reset();
ins(0,0);
vis[now]=1;
int lst=0;
for(int k=fir[now];k!=-1;k=nxt[k])if(!vis[v[k]])lst=v[k];
for(int k=fir[now];k!=-1;k=nxt[k])
{
if(!vis[v[k]])
{
dep[v[k]]=w[k]+mid,dep2[v[k]]=w[k]-mid;
asky(v[k],now);
if(yes)return;
if(v[k]!=lst)addy(v[k],now);
}
}
for(int k=fs[now];k!=-1;k=nt[k])
{gety(vv[k]);if(yes)return;}
}
int main()
{
srand(time(0));
nowsiz=n=read();scanf("%lf",&K);
memset(fir,-1,sizeof(fir));
memset(fs,-1,sizeof(fs));
rep(i,1,n-1){int x=read(),y=read();double z;scanf("%lf",&z);R=max(R,z-K<0.0?K-z:z-K),ade(x,y,z-K),ade(y,x,z-K);}
getwt(1,0,n);
ans=R;
while(R-L>=eps)
{
mid=(R+L)/2.0;yes=0;
rep(i,1,n)vis[i]=0;
gety(root);
if(yes)ans=min(ans,mid),R=mid;
else L=mid;
}
printf("%.0lf",floor(ans));
return 0;
}
并不对劲的uoj276. [清华集训2016]汽水的更多相关文章
- UOJ276 [清华集训2016] 汽水 【二分答案】【点分治】【树状数组】
题目分析: 这种乱七八糟的题目一看就是点分治,答案有单调性,所以还可以二分答案. 我们每次二分的时候考虑答案会不会大于等于某个值,注意到系数$k$是无意义的,因为我们可以通过转化使得$k=0$. 合并 ...
- BZOJ.4738.[清华集训2016]汽水(点分治 分数规划)
BZOJ UOJ 记\(val_i\)是每条边的边权,\(s\)是边权和,\(t\)是经过边数,\(k\)是给定的\(k\). 在点分治的时候二分答案\(x\),设\(|\frac st-k|=x\) ...
- [UOJ#276][清华集训2016]汽水[分数规划+点分治]
题意 给定一棵 \(n\) 个点的树,给定 \(k\) ,求 \(|\frac{\sum w(路径长度)}{t(路径边数)}-k|\)的最小值. \(n\leq 5\times 10^5,k\leq ...
- [UOJ#276]【清华集训2016】汽水
[UOJ#276][清华集训2016]汽水 试题描述 牛牛来到了一个盛产汽水的国度旅行. 这个国度的地图上有 \(n\) 个城市,这些城市之间用 \(n−1\) 条道路连接,任意两个城市之间,都存在一 ...
- UOJ #274. 【清华集训2016】温暖会指引我们前行 [lct]
#274. [清华集训2016]温暖会指引我们前行 题意比较巧妙 裸lct维护最大生成树 #include <iostream> #include <cstdio> #incl ...
- UOJ_274_[清华集训2016]温暖会指引我们前行_LCT
UOJ_274_[清华集训2016]温暖会指引我们前行_LCT 任务描述:http://uoj.ac/problem/274 本题中的字典序不同在于空串的字典序最大. 并且题中要求排序后字典序最大. ...
- UOJ 275. 【清华集训2016】组合数问题
UOJ 275. [清华集训2016]组合数问题 组合数 $C_n^m $表示的是从 \(n\) 个物品中选出 \(m\) 个物品的方案数.举个例子,从$ (1,2,3)(1,2,3)$ 三个物品中选 ...
- UOJ #269. 【清华集训2016】如何优雅地求和
UOJ #269. [清华集训2016]如何优雅地求和 题目链接 给定一个\(m\)次多项式\(f(x)\)的\(m+1\)个点值:\(f(0)\)到\(f(m)\). 然后求: \[ Q(f,n,x ...
- 【UOJ274】【清华集训2016】温暖会指引我们前行 LCT
[UOJ274][清华集训2016]温暖会指引我们前行 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很 ...
随机推荐
- 用SQLLDR来装载date类型的控制文件
以前给山东某单位做oracle数据库恢复得时候,恢复出来得数据中包含date类型,当时给客户提供得是sqlldr得方式,因为数据量比较大,用sqlldr装载起来速度比较快,所以采用了这种方式,结果在装 ...
- 路由选择(codevs 1062)
题目描述 Description 在网络通信中,经常需要求最短路径.但完全用最短路径传输有这样一个问题:如果最终在两个终端节点之间给出的最短路径只有一条.则在该路径中的任一个节点或链路出现故障时,信号 ...
- 子串(codevs 4560)
题目描述 Description 有两个仅包含小写英文字母的字符串A和B.现在要从字符串A中取出k个互不重叠的非空子串,然后把这k个子串按照其在字符串A中出现的顺序依次连接起来得到一个新的字符串,请问 ...
- 12.1——类的定义与声明,隐含的this指针
类的定义与声明: (1)将const放在成员函数的形参列表之后,可以将将成员函数声明为常量,而它的意思是函数不能改变所操作的数据成员 这里必须在声明和定义处都加上const. (2)成员函数有一个隐含 ...
- Shell脚本的编写,sed的使用以及一些正则表达式
Shell脚本的简单编写以及sed的使用 标签(空格分隔): 博客文章 前一阵子为了批量修改Web审计规则,故编写了一个Shell脚本,顺便使用了下sed,顺便把正则表达式也重新学习一遍,感觉还是需要 ...
- yum安装LAMP环境与管理
yum安装LAMP环境与管理 参考:http://www.zixue.it/ yum添加163源 地址: http://mirrors.163.com/.help/centos.html 下载方式: ...
- Sigar 编译笔记
https://blog.csdn.net/zw3413/article/details/79482438
- eslint (js代码检查)
eslint 是一个应用广泛的javascript代码检查工具. 能检测变量名重复等等... 1.安装 npm install -g eslint 2.初始化 会在当前目录下生成一个.eslintrc ...
- Spring中使用构造函数实现Beans自动装配
以下内容引用自http://wiki.jikexueyuan.com/project/spring/beans-auto-wiring/spring-autowiring-by-Constructor ...
- 【Todo】秒杀系统 & 乐观锁 & Nginx反向代理
http://www.csdn.net/article/2014-11-28/2822858 1. 单点帐号验证,不用读,而是用写入,Redis,看是否加watch 2. 抢宝的最终购买冲突.包装称“ ...