两个 log 的做法,开了全局 __int128,第四个样例稳过,但是跑的很慢,加上各种小优化和换桶排序之后快了好几秒,但洛谷上还是 45pts。
个人认为应该不是写错了,单纯跑得慢,求助有没有有效地优化方法!(除了解一元二次方程……)
#include<cstdio>
#include<vector>
#include<algorithm>
#define N 100005
#define int __int128
using namespace std;
inline int read() {
int x=0, f=1;
char ch = getchar();
while(ch<'0' || ch>'9') {
if(ch == '-') f = -1;
ch = getchar();
}
while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48), ch=getchar();
return x*f;
}
inline void write(int x) {
if(x < 0) putchar('-'), x=-x;
if(x > 9) write(x/10);
putchar(x%10+'0');
}
struct Edge {
int v, nex;
} e[N<<1];
int n, a[N], b[N], c[N], vis[N], fa[N], idx, h[N], lst[N], cnt, bs, pla[N];
inline void link(int u, int v) {
e[++idx]={v, h[u]}, h[u]=idx;
e[++idx]={u, h[v]}, h[v]=idx;
}
inline int calc(int i, int l, int r) {
if(c[i] == 0) return b[i]*(r-l+1);
int p = (1-b[i])/c[i];
if(c[i]>0 || r<p) return b[i]*(r-l+1)+c[i]*(l+r)*(r-l+1)/2;
else if(l > p) return r-l+1;
else return b[i]*(p-l+1)+c[i]*(l+p)*(p-l+1)/2+r-p;
}
void dfs(int u) {
for(int i=h[u]; i; i=e[i].nex) {
if(e[i].v == fa[u]) continue;
fa[e[i].v] = u;
dfs(e[i].v);
}
}
bool access(int u) {
if(!vis[fa[u]]) if(!access(fa[u])) return false;
if(++cnt > lst[u]) return false;
vis[u] = 1;
return true;
}
vector<signed> bk[N];
bool check(int limit) {
for(int i=0; i<n; ++i) bk[i].clear();
int pcnt = 0;
for(int u=1; u<=n; ++u) {
if(calc(u, 1, limit) < a[u]) return false;
vis[u]=0, lst[u]=-1;
int l=1, r=limit, mid;
while(l <= r) {
mid = (l+r)>>1;
if(calc(u, mid, limit) >= a[u]) lst[u]=mid, l=mid+1;
else r = mid-1;
}
bk[lst[u]/bs].push_back(u);
}
for(int i=0; i<n; ++i) {
sort(bk[i].begin(), bk[i].end(), [](int x, int y) {
return lst[x] < lst[y];
});
for(auto x : bk[i]) pla[++pcnt] = x;
}
cnt = 0;
for(int i=1; i<=pcnt; ++i) {
if(vis[pla[i]]) continue;
if(!access(pla[i])) return false;
}
return true;
}
signed main() {
n=read(), vis[0]=1, bs=1e9/n+1;
for(int i=1; i<=n; ++i) a[i]=read(), b[i]=read(), c[i]=read();
for(int i=1; i<n; ++i) link(read(), read());
dfs(1);
int l=1, r=1e9, mid, ans;
while(l <= r) {
mid = (l+r)>>1;
if(check(mid)) ans=mid, r=mid-1;
else l = mid+1;
}
write(ans);
return 0;
}