题意:给一棵树每条边有a,b两个值,给你一个m,表示从0到m-1,假设当前为i,那么每条边的权值是a*i+b,求该树任意两点的最大权值

题解:首先我们需要维护出(a,b)的凸壳,对于每个i在上面三分即可,点对用树分治维护,假设当前重心是u,那么把u的直接儿子挨个合并凸壳,这一过程用闵可夫斯基和维护,set启发式合并.

//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize(4)
//#pragma GCC optimize("unroll-loops")
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<bits/stdc++.h>
#define fi first
#define se second
#define db double
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define ld long double
//#define C 0.5772156649
//#define ls l,m,rt<<1
//#define rs m+1,r,rt<<1|1
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define ull unsigned long long
//#define base 1000000000000000000
#define fin freopen("a.txt","r",stdin)
#define fout freopen("a.txt","w",stdout)
#define fio ios::sync_with_stdio(false);cin.tie(0)
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline void sub(ll &a,ll b){a-=b;if(a<0)a+=mod;}
inline void add(ll &a,ll b){a+=b;if(a>=mod)a-=mod;}
template<typename T>inline T const& MAX(T const &a,T const &b){return a>b?a:b;}
template<typename T>inline T const& MIN(T const &a,T const &b){return a<b?a:b;}
inline ll qp(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
inline ll qp(ll a,ll b,ll c){ll ans=1;while(b){if(b&1)ans=ans*a%c;a=a*a%c,b>>=1;}return ans;} using namespace std; const ull ba=233;
const db eps=1e-5;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=100000+10,maxn=100000+10,inf=0x3f3f3f3f; struct FastIO {
static const int S = 1e7;
int wpos;
char wbuf[S];
FastIO() : wpos(0) {}
inline int xchar() {
static char buf[S];
static int len = 0, pos = 0;
if (pos == len)
pos = 0, len = fread(buf, 1, S, stdin);
if (pos == len) exit(0);
return buf[pos++];
}
inline int xuint() {
int c = xchar(), x = 0;
while (c <= 32) c = xchar();
for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
return x;
}
inline int xint()
{
int s = 1, c = xchar(), x = 0;
while (c <= 32) c = xchar();
if (c == '-') s = -1, c = xchar();
for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
return x * s;
}
inline void xstring(char *s)
{
int c = xchar();
while (c <= 32) c = xchar();
for (; c > 32; c = xchar()) * s++ = c;
*s = 0;
}
inline void wchar(int x)
{
if (wpos == S) fwrite(wbuf, 1, S, stdout), wpos = 0;
wbuf[wpos++] = x;
}
inline void wint(ll x)
{
if (x < 0) wchar('-'), x = -x;
char s[24];
int n = 0;
while (x || !n) s[n++] = '0' + x % 10, x /= 10;
while (n--) wchar(s[n]);
wchar('\n');
}
inline void wstring(const char *s)
{
while (*s) wchar(*s++);
}
~FastIO()
{
if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0;
}
} io;
struct edge{int to,Next,a,b;}e[maxn<<1];
int cnt,head[N],sz[N],zx[N],n;
pll dis[N];
bool vis[N];
void init(){cnt=0;memset(head,-1,sizeof head);memset(vis,0,sizeof vis);}
void add(int u,int v,int a,int b){e[cnt].to=v;e[cnt].a=a;e[cnt].b=b;e[cnt].Next=head[u];head[u]=cnt++;}
void dfssz(int u,int f,int &sum)
{
sum++;sz[u]=1;
for(int i=head[u];~i;i=e[i].Next)
{
int x=e[i].to;
if(x==f||vis[x])continue;
dfssz(x,u,sum);sz[u]+=sz[x];
}
}
void dfszx(int u,int f,int sum,int &ans,int &id)
{
zx[u]=sum-sz[u];
for(int i=head[u];~i;i=e[i].Next)
{
int x=e[i].to;
if(x==f||vis[x])continue;
dfszx(x,u,sum,ans,id);
zx[u]=max(zx[u],sz[x]);
}
if(ans>zx[u]){ans=zx[u],id=u;}
}
int findzx(int root)
{
int sum=0;
dfssz(root,-1,sum);
int ans=inf,id=0;
dfszx(root,-1,sum,ans,id);
return id;
} struct Point {
ll x, y;
Point(ll x = 0, ll y = 0) : x(x), y(y) {}
};
typedef Point Vector;
Point operator + (Vector A, Vector B) {return Point(A.x + B.x, A.y + B.y);}
Point operator - (Vector A, Vector B) {return Point(A.x - B.x, A.y - B.y);}
bool operator == (const Vector &A, const Point &B) {return A.x == B.x&& A.y == B.y;}
bool operator < (const Vector &A, const Vector &B) {return A.y < B.y || (A.y == B.y && A.x < B.x);}
ll Cross(Vector A, Vector B) {return A.x * B.y - A.y * B.x;}
int ConvexHull(Point *p, int n, Point *ch) {
sort(p, p + n);
int m = 0;
for(int i = 0; i < n; i++) {
while(m > 1 && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0) m--;
ch[m++] = p[i];
}
int k = m;
for(int i = n - 2; i >= 0; i--) {
while(m > k && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0) m--;
ch[m++] = p[i];
}
return n==1?m:m - 1;
}
int minkowski(Point *a,int &n,Point *b,int &m,Point *c,Point *d)
{
int top=0;
if(n<=2||m<=2)
{
for(int i=0;i<n;i++)for(int j=0;j<m;j++)
d[top++]=a[i]+b[j];
top=ConvexHull(d,top,c);
return top;
}
c[top++]=a[0]+b[0];
for(int i=0,j=0;i<n||j<m;)
{
Point p1=a[i%n]+b[(j+1)%m],p2=a[(i+1)%n]+b[j%m];
if(Cross(p1-c[top-1],p2-c[top-1])>=0)c[top++]=p1,++j;
else c[top++]=p2,++i;
}
return top-1;
}
Point a[N*40],b[N],c[N*4],d[N*4],ans[N*40];
vector<Point>v[N];
int top,la,lb;
void dfsdis(int u,int f,int root)
{
int num=0;
for(int i=head[u];~i;i=e[i].Next)
{
int x=e[i].to;
if(x==f||vis[x])continue;
num++;
dis[x].fi=dis[u].fi+e[i].a;
dis[x].se=dis[u].se+e[i].b;
dfsdis(x,u,root);
}
if(num==0)v[root].pb({dis[u].fi,dis[u].se});
}
void gao(int x)
{
la=0;
for(int i=0;i<v[x].size();i++)a[la++]=v[x][i];
lb=ConvexHull(a,la,b);v[x].clear();
for(int i=0;i<lb;i++)v[x].pb(b[i]);
}
void solve(int root)
{
int p=findzx(root);
v[0].clear();v[0].pb({0,0});
set<pii>s;s.clear();s.insert(mp(v[0].size(),0));
for(int i=head[p];~i;i=e[i].Next)
{
int x=e[i].to;if(vis[x])continue;
v[x].clear();
dis[x]=mp(e[i].a,e[i].b);dfsdis(x,p,x);
gao(x);s.insert(mp(v[x].size(),x));
}
while(s.size()>=2)
{
int x=s.begin()->se;s.erase(s.begin());
int y=s.begin()->se;s.erase(s.begin());
la=lb=0;
for(int i=0;i<v[x].size();i++)a[la++]=v[x][i];
for(int i=0;i<v[y].size();i++)b[lb++]=v[y][i];
int te=minkowski(a,la,b,lb,c,d);
for(int i=0;i<te;i++)ans[top++]=c[i];
for(int i=0;i<v[y].size();i++)v[x].pb(v[y][i]);v[y].clear();
gao(x);s.insert(mp(v[x].size(),x));
}
vis[p]=1;
for(int i=head[p];~i;i=e[i].Next)
{
int x=e[i].to;
if(vis[x])continue;
solve(e[i].to);
}
}
int main()
{
int n=io.xint(),m=io.xint();
init();
for(int i=1;i<n;i++)
{
int u=io.xint(),v=io.xint(),a=io.xint(),b=io.xint();
add(u,v,a,b);add(v,u,a,b);
}
solve(1);
top=ConvexHull(ans,top,a);
for(int i=0;i<m;i++)
{
int l=-1,r=top;
while(l<r-6)
{
int m=(l+r)>>1,m1=(m+r)>>1;
if(a[m].x*i+a[m].y>a[m1].x*i+a[m1].y)r=m1;
else l=m;
}
ll ma=0;
for(int j=max(0,l-10);j<min(top,l+10);j++)ma=max(ma,a[j].x*i+a[j].y);
io.wint(ma);
}
return 0;
}
/******************** ********************/

Codeforces Round #503 (by SIS, Div. 1)E. Raining season的更多相关文章

  1. Codeforces Round #503 (by SIS, Div. 2) Solution

    从这里开始 题目列表 瞎扯 Problem A New Building for SIS Problem B Badge Problem C Elections Problem D The hat P ...

  2. Codeforces Round #503 (by SIS, Div. 2)

    连接:http://codeforces.com/contest/1020 C.Elections 题型:你们说水题就水题吧...我没有做出来...get到了新的思路,不虚.好像还有用三分做的? KN ...

  3. Codeforces Round #503 (by SIS, Div. 2) C. Elections (暴力+贪心)

    [题目描述] Elections are coming. You know the number of voters and the number of parties — n and m respe ...

  4. Codeforces Round #503 (by SIS, Div. 2)-C. Elections

    枚举每个获胜的可能的票数+按照花费排序 #include<iostream> #include<stdio.h> #include<string.h> #inclu ...

  5. Codeforces Round #503 (by SIS, Div. 2) D. The hat

    有图可以直观发现,如果一开始的pair(1,1+n/2)和pair(x, x+n/2)大小关系不同 那么中间必然存在一个答案 简单总结就是大小关系不同,中间就有答案 所以就可以使用二分 #includ ...

  6. Codeforces Round #503 (by SIS, Div. 2)B 1020B Badge (拓扑)

    题目大意:每个同学可以指定一个人,然后构成一个有向图.1-n次查询,从某个人开始并放入一个东西,然后循环,直到碰到一个人已经放过了,就输出. 思路:直接模拟就可以了,O(n^2) 但是O(n)也可以实 ...

  7. Codeforces Round #503 (by SIS, Div. 2) C. Elections(枚举,暴力)

    原文地址 C. Elections time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  8. Codeforces Round #503 (by SIS, Div. 2) D. The hat -交互题,二分

    cf1020D 题意: 交互题目,在有限的询问中找到一个x,使得数列中的第x位和第(x+n/2)位的值大小相同.数列保证相邻的两个差值为1或-1: 思路: 构造函数f(x) = a[x] - a[x ...

  9. Codeforces Round #503 (by SIS, Div. 2) E. Sergey's problem

    E. Sergey's problem [题目描述] 给出一个n个点m条边的有向图,需要找到一个集合使得1.集合中的各点之间无无边相连2.集合外的点到集合内的点的最小距离小于等于2. [算法] 官方题 ...

随机推荐

  1. c# 之系统环境安装

    在重装系统后,对一些原有软件进行了卸载,不知道是什么原因总是提示vs2015 需安装IE10,但是又碰到ie10的一些插件不适合此系统.网上介绍的vs修复没有任何作用 最后找到方法是:重装系统,然后不 ...

  2. [CodeForces 892A] Greed (Java中sort实现从大到小排序)

    题目链接:http://codeforces.com/problemset/problem/892/A 具体的Java 中 sort实现降序排序:https://www.cnblogs.com/you ...

  3. Shiro学习笔记五(Shiro标签,及通配符)

    1.首先是导入标签库 <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %> ...

  4. Latex 左右引号

    参考: LaTeX技巧218:LaTeX如何正确输入引号:双引号""单引号'' Latex 左右引号 在latex中加引号时,使用""的输出为两个同向的引号: ...

  5. Linux命令之nl命令

    nl 命令在 Linux 系统中用来计算文件中行号.nl 可以将输出的文件内容自动的加上行号,其默认的结果和 与 cat -n 有点不太一样,nl 可以将行号做比较多的显示设计,包括位数是否自动补齐 ...

  6. JavaScript中的方法事件和函数的方法的三种方法

    js中的很多事件  而事件相对应的就是方法(函数 )那么今天所说的就是这三种方法      已onclick事件为例 1: 基本方法 <div id="a" onclick= ...

  7. java.lang.TypeNotPresentException: Type javax.xml.bind.JAXBContext not present错误

    今天在搭建spring cloud的时候,发现一直报“java.lang.TypeNotPresentException: Type javax.xml.bind.JAXBContext not pr ...

  8. js全选 反选

    // 全选 反选 allChoose: function (o) { var obj = $.extend(true, { id: "#id", name: "name& ...

  9. Integer的最大值

    来自:https://blog.csdn.net/qq_33611068/article/details/77369050 有这样一道题: 编程测试,遍历 0 到 int所能表示最大的正数,将消耗的时 ...

  10. VS2010:“error C2712: 无法在要求对象展开的函数中使用 __try”

    ZC:这个错误是在使用 "__try{...} __except(EXCEPTION_EXECUTE_HANDLER){}"时 遇到的 http://blog.csdn.net/c ...