ICPC中国南昌国家邀请赛和国际丝绸之路规划大赛预选赛 I J

Posted kls123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ICPC中国南昌国家邀请赛和国际丝绸之路规划大赛预选赛 I J相关的知识,希望对你有一定的参考价值。

I. Max answer

链接:https://nanti.jisuanke.com/t/38228

思路:

枚举最小值,单调栈确定最小值的边界,用线段树+前缀和维护最小值的左右区间

实现代码:

#include<bits/stdc++.h>
using namespace std;
const int M = 3e5+10;
int ls[M*40],rs[M*40],sum[M*40],a[M],b[M],root[M];
int cnt1,cnt,head[M],dep[M],siz[M],fa[M],son[M],wt[M],top[M],tid[M],rk[M];
int idx,tot;
struct node{
    int w,to,next;
}e[M*2];

void add(int u,int v,int c){
    e[++cnt1].to=v;e[cnt1].next=head[u];e[cnt1].w=c;head[u]=cnt1;
    e[++cnt1].to=u;e[cnt1].next=head[v];e[cnt1].w=c;head[v]=cnt1;
}
void dfs1(int u,int faz,int deep){
    dep[u] = deep;
    siz[u] = 1;
    fa[u] = faz;
    for(int i = head[u];i ;i=e[i].next){
        int v = e[i].to;
        if(v != fa[u]){
            wt[v] = e[i].w;
            dfs1(v,u,deep+1);
            siz[u] += siz[v];
            if(son[u]==-1||siz[v]>siz[son[u]])
                son[u] = v;
        }
    }
}

void dfs2(int u,int t){
    top[u] = t;
    tid[u] = tot;
    rk[tot] = wt[u];
    //cout<<1<<endl;
    tot++;
    if(son[u] == -1) return ;
    dfs2(son[u],t);
    for(int i = head[u];i;i=e[i].next){
        int v = e[i].to;
        if(v != son[u]&&v != fa[u])
            dfs2(v,v);
    }
}

void update(int old,int &k,int l,int r,int p){
    k = ++idx;
    ls[k] = ls[old]; rs[k] = rs[old];
    sum[k] = sum[old] + 1;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(p <= mid) update(ls[old],ls[k],l,mid,p);
    else update(rs[old],rs[k],mid+1,r,p);
}

int query(int old,int k,int L,int R,int l,int r){
    if(L <= l&&R >= r) return sum[k] - sum[old];
    int mid = (l + r) >> 1;
    int ret = 0;
    if(L <= mid) ret += query(ls[old],ls[k],L,R,l,mid);
    if(R > mid) ret += query(rs[old],rs[k],L,R,mid+1,r);
    return ret;
}

int ask(int x,int y,int l,int r){
    int ans = 0;
    int fx = top[x],fy = top[y];
    while(fx != fy){
        if(dep[fx] < dep[fy]) swap(fx,fy),swap(x,y);
        if(fx == 1) ans += query(root[tid[fx]],root[tid[x]],l,r,1,cnt);
        else ans += query(root[tid[fa[fx]]],root[tid[x]],l,r,1,cnt);
        x = fa[fx]; fx = top[x];
    }
    if(x==y) return ans; 
    if(dep[x] > dep[y]) swap(x,y);
    ans += query(root[tid[x]],root[tid[y]],l,r,1,cnt);
    return ans;
}

void dfs(int u,int fa){
    update(root[tid[fa]],root[tid[u]],1,cnt,wt[u]);
    for(int i = head[u];i;i=e[i].next){
        int v = e[i].to;
        if(v == fa) continue;
        dfs(v,u);
    }
}

int l[M],r[M],x[M],u[M],v[M],w[M];
int Find(int x){
    int num = lower_bound(b+1,b+1+cnt,x)-b;
    return num;
}

int main()
{
    int m,n;
    scanf("%d%d",&n,&m); tot = 1;
    memset(son,-1,sizeof(son));
    for(int i = 1;i < n;i ++){
        scanf("%d%d%d",&u[i],&v[i],&w[i]);
        b[i] = w[i];
    }
    for(int i = 1;i <= m;i ++){
        scanf("%d%d%d",&l[i],&r[i],&x[i]);
        b[i+n-1] = x[i];
    }
    sort(b+1,b+n+m);
    cnt = unique(b+1,b+n+m)-b;
    for(int i = 1;i < n;i ++){
        int num = Find(w[i]);
        add(u[i],v[i],num);
    }
    dfs1(1,0,1); dfs2(1,1);dfs(1,0);
    for(int i = 1;i <= m;i ++){
        int num = Find(x[i]);
        printf("%d
",ask(l[i],r[i],1,num));
    }
}

J. Distance on the tree

链接:https://nanti.jisuanke.com/t/38229

思路;

nmd,弱智题写到比赛结束都没写来,

序列上求任意区间有多少个数小于k

https://www.cnblogs.com/kls123/p/9568553.html

就是这道题扔到树上,一开始想复杂了,还以为是点对的数量。

从根节点开始遍历每次遍历到一条边看作是一次修改,下标为val的点+1

后面发现这种方法建的主席树是类似权值线段树的,下标和树是没关系的,有关系的是这是第几次修改的,在树上应该用root去跳,

之前一直wa,wa的自闭,后面nmd发现之前的板子错了,  在树上跳的时候应该用fa[],son[],而不是+1,-1.

 

实现代码:

#include<bits/stdc++.h>
using namespace std;
const int M = 3e5+10;
int ls[M*40],rs[M*40],sum[M*40],a[M],b[M],root[M];
int cnt1,cnt,head[M],dep[M],siz[M],fa[M],son[M],wt[M],top[M],tid[M],rk[M];
int idx,tot;
struct node{
    int w,to,next;
}e[M*2];

void add(int u,int v,int c){
    e[++cnt1].to=v;e[cnt1].next=head[u];e[cnt1].w=c;head[u]=cnt1;
    e[++cnt1].to=u;e[cnt1].next=head[v];e[cnt1].w=c;head[v]=cnt1;
}
void dfs1(int u,int faz,int deep){
    dep[u] = deep;
    siz[u] = 1;
    fa[u] = faz;
    for(int i = head[u];i ;i=e[i].next){
        int v = e[i].to;
        if(v != fa[u]){
            wt[v] = e[i].w;
            dfs1(v,u,deep+1);
            siz[u] += siz[v];
            if(son[u]==-1||siz[v]>siz[son[u]])
                son[u] = v;
        }
    }
}

void dfs2(int u,int t){
    top[u] = t;
    tid[u] = tot;
    rk[tot] = wt[u];
    //cout<<1<<endl;
    tot++;
    if(son[u] == -1) return ;
    dfs2(son[u],t);
    for(int i = head[u];i;i=e[i].next){
        int v = e[i].to;
        if(v != son[u]&&v != fa[u])
            dfs2(v,v);
    }
}

void update(int old,int &k,int l,int r,int p){
    k = ++idx;
    ls[k] = ls[old]; rs[k] = rs[old];
    sum[k] = sum[old] + 1;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(p <= mid) update(ls[old],ls[k],l,mid,p);
    else update(rs[old],rs[k],mid+1,r,p);
}

int query(int old,int k,int L,int R,int l,int r){
    if(L <= l&&R >= r) return sum[k] - sum[old];
    int mid = (l + r) >> 1;
    int ret = 0;
    if(L <= mid) ret += query(ls[old],ls[k],L,R,l,mid);
    if(R > mid) ret += query(rs[old],rs[k],L,R,mid+1,r);
    return ret;
}

int ask(int x,int y,int l,int r){
    int ans = 0;
    int fx = top[x],fy = top[y];
    while(fx != fy){
        if(dep[fx] < dep[fy]) swap(fx,fy),swap(x,y);
        if(fx == 1) ans += query(root[tid[fx]],root[tid[x]],l,r,1,cnt);
        else ans += query(root[tid[fa[fx]]],root[tid[x]],l,r,1,cnt);
        x = fa[fx]; fx = top[x];
    }
    if(x==y) return ans; 
    if(dep[x] > dep[y]) swap(x,y);
    ans += query(root[tid[x]],root[tid[y]],l,r,1,cnt);
    return ans;
}

void dfs(int u,int fa){
    update(root[tid[fa]],root[tid[u]],1,cnt,wt[u]);
    for(int i = head[u];i;i=e[i].next){
        int v = e[i].to;
        if(v == fa) continue;
        dfs(v,u);
    }
}

int l[M],r[M],x[M],u[M],v[M],w[M];
int Find(int x){
    int num = lower_bound(b+1,b+1+cnt,x)-b;
    return num;
}

int main()
{
    int m,n;
    scanf("%d%d",&n,&m); tot = 1;
    memset(son,-1,sizeof(son));
    for(int i = 1;i < n;i ++){
        scanf("%d%d%d",&u[i],&v[i],&w[i]);
        b[i] = w[i];
    }
    for(int i = 1;i <= m;i ++){
        scanf("%d%d%d",&l[i],&r[i],&x[i]);
        b[i+n-1] = x[i];
    }
    sort(b+1,b+n+m);
    cnt = unique(b+1,b+n+m)-b;
    for(int i = 1;i < n;i ++){
        int num = Find(w[i]);
        add(u[i],v[i],num);
    }
    dfs1(1,0,1); dfs2(1,1);dfs(1,0);
    for(int i = 1;i <= m;i ++){
        int num = Find(x[i]);
        printf("%d
",ask(l[i],r[i],1,num));
    }
}

 

以上是关于ICPC中国南昌国家邀请赛和国际丝绸之路规划大赛预选赛 I J的主要内容,如果未能解决你的问题,请参考以下文章

ACM国际大学生程序设计大赛(ICPC)

icpc 南昌邀请赛网络赛 Subsequence

2019 ACM - ICPC 全国邀请赛(南昌) 题解(9 / 12)

2019 ICPC南昌邀请赛比赛过程及题解

2019ICPC南昌邀请赛现场赛A题 - Attack(斯坦纳树)

中国(郑州)国际海绵城市建设与水系规划治理展览会