#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<iomanip>
#include<bitset>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#define ll long long
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define chu printf
#define inf 0x7fffffff
#define lson t[rt].ls//(rt<<1) (rt<<1)|1
#define rson t[rt].rs
using namespace std;
inline int re()
{
int x=0,h=1;char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')h=-1;ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();
}
return x*h;
}
const int N=20,M;
struct node
{
ll sum,ans;
in ls,rs;
}t[N];
int tot=0;
ll query(int rt,int l,int r,int L,int R)
{
if(!rt)return 0;
if(L<=l&&r<=R)return t[rt].sum;
ll ans=0;
int mid=(l+r)>>1;
if(L<=mid)ans+=query(lson,l,mid,L,R);
if(R>mid)ans+=query(rson,mid+1,r,L,R);//rson类似指针,节点存储区间
return ans;
}//维护区间和
void update(int rt,int l,int r,int pos,int val)
{
if(!rt)
{
rt=++tot;//不存在先新建 ,左右孩子都没有用到暂时没有
}
if(l==r)
{
t[rt].sum+=val;//完全恢复基础线段树步骤
return;
}
int mid=(l+r)>>1;
if(pos<=mid)update(lson,l,mid,pos,val);
else update(rson,mid+1,r,pos,val);
t[rt].sum=t[lson].sum+t[rson].sum;//pushup()
}
//以下是权值线段树的用法
//查询>=L <=R的数的个数
int query(int rt,int l,int r,int L,int R)
{
if(!rt)return 0;
if(L<=l&&r<=R)return t[rt].cnt;
int mid=(l+r)>>1;int ans=0
if(L<=mid)ans+=query(lson,l,mid,L,R);
if(R>mid)ans+=query(rson,mid+1,r,L,R);
return ans;
}
//查询第k大的数是谁
int queryk(int rt,int l,int r,int k)
{
if(!rt)return -inf;//表示不存在
if(l==r)return t[rt].num;//这个位置代表的数,本来应该是t[rt].l或者rt[rt].r都行吧,但是做了离散可能就不一样了
int mid=(l+r)>>1;
if(k>t[rson].cnt)//要查的在左边
{
return queryk(lson,l,mid,k-t[rson].cnt);//右边的那些数就不算了
}
else
return queryk(rson,mid+1,r,k);
}
int lcount(int val)
{
return query(root,L,R,L,val-1);//查询比val小的数的个数
}
int getrank(int val)//val的升序排名
{
return lcount(val)+1;
}
int pre(int val)
{
int x=lcount(val);//先找比它小的第一个数排名
return queryk(root,L,R,x);
}
void pushup(int rt)//更新父节点最大值
{
}
void update()
int segmerge(int ra,int rb,int l,int r)
{
if(!ra)return rb;
if(!rb)return ra;//合并树
if(l==r)
{
t[ra].sum+=t[rb].sum;//同一颜色次数累加
t[ra].ans=l;return ra;//返回当前更新完的节点编号
}
int mid=(l+r)>>1;
lson(ra)=segmerge(lson(ra),lson(rb),l,mid);//因为一直传的同意区间,所以lson(ra),lson(rb一定代表同一个区间
rson(ra)=segmerge(rson(ra),rson(rb),mid+1,r);
pushup(ra);//把ra改了,它的父亲要回溯
return ra;
}
void dfs(int now,int fa)
{
for(int i=head[now];i;i=e[i].nex)
{
int to=e[i].to;
if(to==fa)continue;
dfs(to,now);
segmerge(rt[now],rt[to],1,n);
}
update(rt[now],1,n,col[now],1);
ans[now]=t[rt[now]].ans;
}//rt[i]=k代表颜色树节点对应dfs序列数
/*
*