Submission #281586

#TimeUsernameProblemLanguageResultExecution timeMemory
281586MKopchevConstruction of Highway (JOI18_construction)C++14
100 / 100
748 ms29416 KiB
#include<bits/stdc++.h>
using namespace std;
const int nmax=1e5+42;

int n,inp[nmax],help[nmax];

void compress()
{
    for(int i=1;i<=n;i++)help[i]=inp[i];
    sort(help+1,help+n+1);

    for(int i=1;i<=n;i++)
    {
        inp[i]=lower_bound(help+1,help+n+1,inp[i])-help;
    }
}

pair<int,int> edges[nmax];

vector<int> adj[nmax];

int parent[nmax];

int heaviest[nmax];

int SZ[nmax];

void dfs(int node,int par)
{
    SZ[node]=1;
    parent[node]=par;

    for(auto k:adj[node])
        if(k!=par)
        {
            dfs(k,node);
            SZ[node]+=SZ[k];

            if(SZ[k]>SZ[heaviest[node]])heaviest[node]=k;
        }

}

struct info
{
    int mini,maxi,lazy;
};

vector< int > path[nmax];

vector< info > tree[nmax];

void push(int id,int node)
{
    if(tree[id][node].lazy!=-1)
    {
        tree[id][node*2].lazy=tree[id][node].lazy;
        tree[id][node*2+1].lazy=tree[id][node].lazy;
    }
    tree[id][node].lazy=-1;
}

info actual(info ret)
{
    if(ret.lazy!=-1)
    {
        ret.mini=ret.lazy;
        ret.maxi=ret.lazy;
    }
    ret.lazy=-1;
    return ret;
}
info my_merge(info l,info r)
{
    l=actual(l);
    r=actual(r);

    info ret;
    ret.lazy=-1;
    ret.mini=min(l.mini,r.mini);
    ret.maxi=max(l.maxi,r.maxi);
    return ret;
}
void update(int id,int node,int l,int r,int lq,int rq,int val)
{
    //cout<<"update "<<id<<" "<<node<<" "<<l<<" "<<r<<" "<<lq<<" "<<rq<<" "<<val<<endl;

    if(l==lq&&r==rq)
    {
        tree[id][node].lazy=val;
        return;
    }

    push(id,node);

    int av=(l+r)/2;

    if(lq<=av)update(id,node*2,l,av,lq,min(av,rq),val);
    if(av<rq)update(id,node*2+1,av+1,r,max(av+1,lq),rq,val);

    tree[id][node]=my_merge(tree[id][node*2],tree[id][node*2+1]);
}

int query(int id,int node,int l,int r,int pos)
{
    if(l==r)return actual(tree[id][node]).mini;

    push(id,node);

    int av=(l+r)/2,mem;

    if(pos<=av)mem=query(id,node*2,l,av,pos);
    else mem=query(id,node*2+1,av+1,r,pos);

    tree[id][node]=my_merge(tree[id][node*2],tree[id][node*2+1]);
    return mem;
}

int query_range(int id,int node,int l,int r,int lq,int rq,int val)
{
    //cout<<"query_range "<<id<<" "<<node<<" "<<l<<" "<<r<<" "<<lq<<" "<<rq<<" "<<val<<" "<<tree[id][node].lazy<<" "<<tree[id][node].mini<<" "<<tree[id][node].maxi<<endl;

    if(tree[id][node].lazy!=-1)
    {
        //cout<<"go go "<<lq<<" "<<rq<<" "<<tree[id][node].lazy<<endl;

        if(tree[id][node].lazy==val)return lq;
        return rq+1;
    }

    if(tree[id][node].maxi<val||tree[id][node].mini>val)return rq+1;

    push(id,node);

    int av=(l+r)/2;

    if(av<rq)
    {
        int mem=query_range(id,node*2+1,av+1,r,max(lq,av+1),rq,val);

        if(mem!=max(lq,av+1))
        {
            tree[id][node]=my_merge(tree[id][node*2],tree[id][node*2+1]);
            return mem;
        }
    }

    if(lq<=av)
    {
        int mem=query_range(id,node*2,l,av,lq,min(av,rq),val);

        if(mem!=lq)
        {
            tree[id][node]=my_merge(tree[id][node*2],tree[id][node*2+1]);
            return mem;
        }
    }

    tree[id][node]=my_merge(tree[id][node*2],tree[id][node*2+1]);
    return lq;
}
int on_which[nmax];

int id[nmax];

void create_paths(int node,int par,int root)
{
    on_which[node]=root;
    id[node]=path[root].size();
    path[root].push_back(node);

    //cout<<node<<" -> "<<on_which[node]<<" "<<id[node]<<endl;

    for(auto k:adj[node])
        if(k!=par)
        {
            if(k==heaviest[node])create_paths(k,node,root);
            else create_paths(k,node,k);
        }
}

int fenwick[nmax];

int ask(int pos)
{
    int ret=0;
    while(pos)
    {
        ret+=fenwick[pos];
        pos=pos-(pos&(-pos));
    }
    return ret;
}

void upd(int pos,int val)
{
    while(pos<=n)
    {
        fenwick[pos]+=val;
        pos=pos+(pos&(-pos));
    }
}

long long eval(vector< pair<int/*value*/,int/*how much*/> > given)
{
    long long outp=0;

    for(auto k:given)
    {
        outp=outp+1LL*k.second*ask(k.first-1);

        upd(k.first,k.second);
    }

    for(auto k:given)
    {
        upd(k.first,-k.second);
    }

    return outp;
}

int main()
{
    scanf("%i",&n);
    for(int i=1;i<=n;i++)scanf("%i",&inp[i]);

    compress();

    for(int i=1;i<n;i++)
    {
        scanf("%i%i",&edges[i].first,&edges[i].second);

        adj[edges[i].first].push_back(edges[i].second);
        adj[edges[i].second].push_back(edges[i].first);
    }

    dfs(1,0);

    create_paths(1,0,1);

    for(int i=1;i<=n;i++)
    {
        while(tree[i].size()<4*path[i].size())
        {
            info cur;
            cur.lazy=-1;
            cur.maxi=-1;
            cur.mini=1e9;

            tree[i].push_back(cur);
        }
    }

    for(int i=1;i<=n;i++)
    {
        //cout<<"i= "<<i<<endl;

        update(on_which[i],1,0,path[on_which[i]].size()-1,id[i],id[i],inp[i]);
    }

    for(int i=1;i<n;i++)
    {
        int where=edges[i].first;

        int new_val=inp[edges[i].second];

        vector< pair<int/*value*/,int/*how much*/> > given={};

        while(where)
        {
            //cout<<"where= "<<i<<" "<<where<<endl;

            int cur_value=query(on_which[where],1,0,path[on_which[where]].size()-1,id[where]);

            int le=query_range(on_which[where],1,0,path[on_which[where]].size()-1,0,id[where],cur_value);

            //cout<<"range: "<<le<<" "<<id[where]<<" "<<cur_value<<endl;

            given.push_back({cur_value,id[where]-le+1});

            update(on_which[where],1,0,path[on_which[where]].size()-1,le,id[where],inp[edges[i].second]);

            where=path[on_which[where]][le];
            where=parent[where];

            //system("pause");
        }

        printf("%lld\n",eval(given));
    }
    return 0;
}

Compilation message (stderr)

construction.cpp: In function 'int main()':
construction.cpp:266:13: warning: unused variable 'new_val' [-Wunused-variable]
  266 |         int new_val=inp[edges[i].second];
      |             ^~~~~~~
construction.cpp:225:10: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
  225 |     scanf("%i",&n);
      |     ~~~~~^~~~~~~~~
construction.cpp:226:31: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
  226 |     for(int i=1;i<=n;i++)scanf("%i",&inp[i]);
      |                          ~~~~~^~~~~~~~~~~~~~
construction.cpp:232:14: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
  232 |         scanf("%i%i",&edges[i].first,&edges[i].second);
      |         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...