ICM Technex 2018 and Codeforces Round #463 (Div. 1 + Div. 2, combined)

还是太菜了,码力小,很多题都不会做

前言

春节打的比赛
本来可以上紫了,迷之跳过C掉了分QAQ

比赛过程:
看完A,觉得太水不科学,多看了几次。。
看完B,觉得太水不科学,多看了几次。。
然后看了E不会做
看了D不是很看得懂
看了F好像有搞头
看了C,看了半天没看到题面有输出任意一组解的意思,T2都有ans of them。。
然后觉得理解错题意了。。
就跳过了

开始刚F
刚啊刚
过了样例
WA了pre3,手出数据
过了pre3,WA了pre6
写个对拍,终于过了

比赛还有十多分钟
闲逛了一下
决定做C

但是感觉题意还是理解不对
看看时间还有5分钟

决定随便打一打。。
于是打了三分钟。。
样例都不管就交了。。
发现WApre3
早上发现是-1点
判了-1就A了

哇,这是什么东西啊。。
C题三分钟的题没有做。。
做了个只有89个人做的F
C题当时也有1200+分的,我的F也就只有1200分QAQ
真的大失败

题解?

A:
由于长度只有1000,所以再反过来输出还想可以啊。。

太水了,多看了好多次题面,你说是A题也不可以这么水吧。。

B:
直接O(1000000)预处理
爱怎么搞怎么搞

太水了,多看了好多次题面,你说是B题也不可以这么水吧。。

C:
直接没有用多少个长度为a的循环节,长度为b的循环节就可以了

太水了,题面还有没说任意一组解,于是看了好多次题面,你说是C题也不可以水+描述不够吧,就是没有判-1点,WA掉了,我真是。。。。。

F:
子树问题,容易想到dus on tree
然后这种类似于插入一次函数的东西,容易想到超哥线段树
每一个点就是插入一个斜率为 b[x] b [ x ] ,截距为 ans[x] a n s [ x ] 的直线
对于重儿子的子树,写一个超哥线段树维护一下就可以了
时间复杂度 O(nlog2n) O ( n l o g 2 n )
一开始因为dsu写错WA了好多发QAQ
CODE:


 #include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL MAX=(1LL<<55);
const LL N=100005;
struct qq
{
    LL x,y,last;
}e[N*2];LL num,last[N];
LL n;
LL a[N],B[N];
void init (LL x,LL y)
{
    num++;
    e[num].x=x;e[num].y=y;
    e[num].last=last[x];
    last[x]=num;
}
LL ans[N];
LL tot[N],son[N];
void dfs (LL x,LL fa)
{
    tot[x]=1;
    for (LL u=last[x];u!=-1;u=e[u].last)
    {
        LL y=e[u].y;
        if (y==fa) continue;
        dfs(y,x);
        tot[x]+=tot[y];
        if (tot[y]>tot[son[x]]) son[x]=y;
    }
}
LL s1[N*8],s2[N*8],k[N],b[N];//�����߶���
LL tr[N*8];
LL root;
bool Jud (LL x,LL y,LL pos)//��pos����ط���x�᲻�����yҪ�� 
{
    return b[x]+k[x]*pos<b[y]+k[y]*pos;
}
void change (LL &now,LL l,LL r,LL x)
{
    if (now==0) 
    {
        now=++num;
        tr[now]=x;
        s1[now]=0;s2[now]=0;
        return ;
    }
    if (l==r)
    {
        if (Jud(x,tr[now],l))
            tr[now]=x;
        return ;
    }
    LL mid=(l+r)>>1;
    if (k[x]<k[tr[now]])//������б�ʸ�С
    {
        if (Jud(x,tr[now],mid))//������ʱ�����Ѿ������ˣ���ô�ұ߾�û��
            change(s1[now],l,mid,tr[now]),tr[now]=x;
        else
            change(s2[now],mid+1,r,x); 
    }
    else
    {
        if (Jud(x,tr[now],mid))
            change(s2[now],mid+1,r,tr[now]),tr[now]=x;
        else change(s1[now],l,mid,x);
    }
}
LL get (LL x,LL y)
{
    return k[x]*y+b[x];
}
LL get_min (LL now,LL l,LL r,LL x)
{
    if (now==0) return MAX;  
    LL mid=(l+r)>>1;
    LL ans=get(tr[now],x);
//  printf("%I64d %I64d %I64d %I64d %I64d %I64d %I64d\n",now,l,r,tr[now],ans,k[tr[now]],b[tr[now]]);
    if (x<=mid) ans=min(ans,get_min(s1[now],l,mid,x));
    else ans=min(ans,get_min(s2[now],mid+1,r,x));
    return ans; 
}
void Dfs (LL xx,LL x,LL fa)
{
    ans[xx]=min(ans[xx],ans[x]+B[x]*a[xx]);
    change(root,-100000,100000,x);
    for (LL u=last[x];u!=-1;u=e[u].last)
    {
        LL y=e[u].y;
        if (y==fa) continue;
        Dfs(xx,y,x);
    }
}
void solve (LL x,LL fa)
{
    if (son[x]==0)//Ҷ�� 
    {
        k[x]=B[x];b[x]=0;
        change(root,-100000,100000,x);
        return ;
    }
    for (LL u=last[x];u!=-1;u=e[u].last)
    {
        LL y=e[u].y;
        if (y==fa||y==son[x]) continue;
        solve(y,x);
    }
    root=num=0;
    solve(son[x],x);
    //printf("%d\n",x);
    ans[x]=get_min(root,-100000,100000,a[x]);
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==fa||y==son[x]) continue;
        Dfs(x,y,x);
    }
    k[x]=B[x];b[x]=ans[x];
    change(root,-100000,100000,x);
}
int main()
{
    num=0;memset(last,-1,sizeof(last));
    scanf("%I64d",&n);
    for (LL u=1;u<=n;u++)   scanf("%I64d",&a[u]);
    for (LL u=1;u<=n;u++) scanf("%I64d",&B[u]);
    for (LL u=1;u<n;u++)
    {
        LL x,y;
        scanf("%I64d%I64d",&x,&y);
        init(x,y);init(y,x);
    }
    dfs(1,0);
//  for (int u=1;u<=n;u++) printf("%I64d %I64d\n",u,son[u]);
    num=0;
    solve(1,0);
    for (LL u=1;u<=n;u++) printf("%I64d ",ans[u]);
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值