当前位置: 代码迷 >> 综合 >> 【线段树】[LUOGU [USACO17JAN]Promotion Counting晋升者计数] 线段树合并
  详细解决方案

【线段树】[LUOGU [USACO17JAN]Promotion Counting晋升者计数] 线段树合并

热度:57   发布时间:2024-01-17 00:03:39.0

题目:

题目链接:[LUOGU [USACO17JAN]Promotion Counting晋升者计数]
题解:

这是个线段树合并的板子题,,,可以主席树写,可以树状数组(竟然还有莫队优化+BIT的写法,,,菜鸡我竟然没想到),甚至是Splay也可以写,,但是我偏要写线段树合并,,o(?^`)o,,

在前面处理一下点权,这里的点权可以用比较巧妙的一个小trick即可,然后这个线段树合并就非常的板子了,,

最后放一个自己模拟的权值线段树的合并,,(比较菜,,,画了几十分钟,,,)
在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int s=0,w=1;char ch=getchar();while(ch>'9'||ch<'0'){
    if(ch=='-')w=-1;ch=getchar();}while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();return s*w;
}
const int sea=1e5+7;
struct hit{
    int ls,rs,sum;}tr[sea*40];//这里的sum就是答案 
struct beat{
    int id,w;}b[sea];
struct sea{
    int ver,next;}e[sea<<1];
int n,cnt,seg,tot,root[sea],last[sea],a[sea],ans[sea];
bool cmp(beat x,beat y){
    return x.w<y.w;}
void add(int x,int y){
    e[++tot].ver=y,e[tot].next=last[x];last[x]=tot;}
void build(int &k,int l,int r,int val)
{
    if(!k) k=++seg; tr[k].sum++;//答案的初值都是1 if(l==r) return ;int mid=(l+r)/2;if(val<=mid) build(tr[k].ls,l,mid,val);else build(tr[k].rs,mid+1,r,val);
}
int incor(int x,int y)
{
    if(!x) return y; if(!y) return x;tr[x].ls=incor(tr[x].ls,tr[y].ls);tr[x].rs=incor(tr[x].rs,tr[y].rs);tr[x].sum=(tr[tr[x].ls].sum+tr[tr[x].rs].sum);return x;
}
int ask(int k,int l,int r,int val)
{
    int s=0; if(!k) return 0;if(val<=l) return tr[k].sum;int mid=(l+r)/2;if(val<=mid) s=ask(tr[k].ls,l,mid,val)+ask(tr[k].rs,mid+1,r,val);else s=ask(tr[k].rs,mid+1,r,val);return s;
}
void dfs(int x,int fa)
{
    for(int i=last[x];i;i=e[i].next){
    int y=e[i].ver;	if(y==fa) continue; dfs(y,x); incor(root[x],root[y]);}build(root[x],1,cnt,a[x]);ans[x]=ask(root[x],1,cnt,a[x]+1);//这里的加一是必要的因为在ask里面
}
int main()
{
    n=read();for(int i=1;i<=n;i++) root[i]=i,b[i].id=i,b[i].w=read();sort(b+1,b+n+1,cmp); cnt=0; seg=n;for(int i=1;i<=n;i++) if(b[i].w>b[i-1].w) a[b[i].id]=++cnt; else a[b[i].id]=cnt;//这样按照权值排过序之后就不需要再用离散化等什么的操作对1e9进行优化了//这时的a[]数组中存的就是排过序之后的序号的排序(非去重)//这时就作为这棵树上的所有点权就好 
// for(int i=1;i<=n;i++) printf("%d ",a[i]);puts(" ");for(int i=2,x;i<=n;i++)	x=read(),add(i,x),add(x,i);dfs(1,0); for(int i=1;i<=n;i++) printf("%d\n",ans[i]);return 0;
}

Continue……