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的主要内容,如果未能解决你的问题,请参考以下文章
2019 ACM - ICPC 全国邀请赛(南昌) 题解(9 / 12)