板子就是同时在两个线段树上走,然后合并信息,一般是权值线段树

板题:

luogu_P3605

求子树内有多少比此点权值大的(类似逆序对

用线段树合并做就是每个点维护权值线段树,每dfs到一个点就dfs并合并它所有儿子的线段树,查询答案

#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define mid ((l+r)>>1)
using namespace std;
const int maxn=100009;
int n,tot,cnt;
struct node{
    int sum,l,r;
}t[maxn*30];
int ls[maxn*30],rs[maxn*30],root[maxn];
inline void upd(int x){
    t[x].sum=t[ls[x]].sum+t[rs[x]].sum;
}
void build(int &x,int l,int r,int pos){
    x=++tot;t[x].l=l;t[x].r=r;
    if(l==r){
        t[x].sum=1;return;
    }
    if(pos<=mid)build(ls[x],l,mid,pos);
    else build(rs[x],mid+1,r,pos);
    upd(x);
}
void change(int x,int l,int r,int pos){
    if(l==r){
        t[x].sum++;return;
    }
    if(pos<=mid)change(ls[x],l,mid,pos);
    else change(rs[x],mid+1,r,pos);
    upd(x);
}
int merge(int x,int y){
    if(!x||!y)return x+y;
    if(t[x].l==t[x].r){
        t[x].sum+=t[y].sum;
        return x;
    }
    ls[x]=merge(ls[x],ls[y]);
    rs[x]=merge(rs[x],rs[y]);
    upd(x);
    return x;
}
int query(int x,int l,int r,int L,int R){
    if(x==0)return 0;
    if(L<=l&&r<=R)return t[x].sum;
    int ans=0;
    if(L<=mid)ans+=query(ls[x],l,mid,L,R);
    if(R>mid)ans+=query(rs[x],mid+1,r,L,R);
    return ans;
}
int a[maxn],hsh[maxn],fa[maxn];
vector<int>e[maxn];
int ans[maxn];
void dfs(int x){
    int c=e[x].size();
    for(int i=0;i<c;i++){
        dfs(e[x][i]);
        root[x]=merge(root[x],root[e[x][i]]);
    }
    ans[x]=query(root[x],1,cnt,a[x]+1,cnt);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),hsh[i]=a[i];
    for(int i=2,x;i<=n;i++)scanf("%d",&x),e[x].pb(i);
    sort(hsh+1,hsh+1+n);
    cnt=unique(hsh+1,hsh+1+n)-hsh-1;
    for(int i=1;i<=n;i++)a[i]=lower_bound(hsh+1,hsh+1+cnt,a[i])-hsh,
    build(root[i],1,cnt,a[i]);
    dfs(1);
    for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
}

CF600E

一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和

同上题

#include<bits/stdc++.h>
#define ll long long
#define mid ((l+r)>>1)
using namespace std;
const int maxn=100009;
int n,tot;
struct node{
    int mx;ll id;
}t[maxn*30];
int ls[maxn*30],rs[maxn*30];
inline void upd(int x){
    if(t[ls[x]].mx>t[rs[x]].mx)t[x].mx=t[ls[x]].mx,t[x].id=t[ls[x]].id;
    else if(t[ls[x]].mx<t[rs[x]].mx)t[x].mx=t[rs[x]].mx,t[x].id=t[rs[x]].id;
    else t[x].mx=t[ls[x]].mx,t[x].id=t[ls[x]].id+t[rs[x]].id;
}
void build(int &x,int l,int r,int pos){
    x=++tot;
    if(l==r){
        t[x].id=l;
        t[x].mx++;
        return;
    }
    if(pos<=mid)build(ls[x],l,mid,pos);
    else build(rs[x],mid+1,r,pos);
    upd(x);
}
void change(int x,int l,int r,int pos){
    if(l==r){
        t[x].mx++;
        return;
    }
    if(pos<=mid)change(ls[x],l,mid,pos);
    else change(rs[x],mid+1,r,pos);
    upd(x);
}
int merge(int x,int y,int l,int r){
    if(!x||!y)return x+y;
    if(l==r){
        t[x].mx+=t[y].mx;
        return x;
    }
    ls[x]=merge(ls[x],ls[y],l,mid);
    rs[x]=merge(rs[x],rs[y],mid+1,r);
    upd(x);
    return x;
}
int root[maxn];
ll ans[maxn];
struct nod{
    int v,nxt;
}e[maxn<<1];
int head[maxn],cnt;
inline void add(int u,int v){
    e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt;
}
void dfs(int x,int fa){
    for(int i=head[x];i;i=e[i].nxt){
        if(e[i].v==fa)continue;
        dfs(e[i].v,x);
        root[x]=merge(root[x],root[e[i].v],1,n);
    }
    ans[x]=t[root[x]].id;
}
int c[maxn];
signed main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&c[i]),build(root[i],1,n,c[i]);
    for(int i=1,u,v;i<n;i++){
        scanf("%d%d",&u,&v);add(u,v);add(v,u);
    }
    dfs(1,0);
    for(int i=1;i<=n;i++)printf("%lld ",ans[i]);
}
02-10 10:41