1 条题解
-
0
好抽象的题目名。
处理子树问题很常见的方法是转dfs序,因为子树在dfs序上连续,这样就可以愉快的处理序列问题了。
不动脑子的方法是主席树或者dsu。
但是我是二维偏序魔怔人。二位数点真的很好用啊就是得做上十几道题才能想明白各种各样的偏序关系。
以我的经验来说,哪怕你知道可以偏序做也不要直接想怎么套板子(非常容易想乱)。先把问题抽象成形式化的偏序关系,再去想怎么维护偏序。
具体来说,这个题就是求区间 中有多少个大于 的数。
把问题裂开:
-
在原题里表示当前节点, 表示子树的最后一个元素,也就是 , 表示以 i 为根的子树大小
-
剩下普通一个序列问题
再把问题分解:
分别求 中大于 的数的个数再相减即为答案。
这就是两个很普通的二维偏序。
其实剩下的难度全在代码实现,这个真的只能靠自己理解了,要时刻记得,先排序保证第一维有序,统计某个节点时第二维可能合法的点一定要全都在树状数组里,然后用树状数组筛选第二维合法的点。
对于这个题来说要分清两位的实际意义,一个是原序列中的顺序,另一个是值域。
代码有些难看
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> #include<cstring> #define int long long using namespace std; const int N=1e5+17; struct node{ int nxt,to; }q[N*2];int head[N],cnt,n; struct query{ int id,l,r,x,ans; }e[N],tmp[N];int v[N],b[N],siz[N],c[N]; void add(int x,int y){ q[++cnt].nxt=head[x]; q[cnt].to=y; head[x]=cnt; }int dfn[N],dfc; void dfs(int x,int fa){ siz[x]=1;dfn[x]=++dfc; for(int i=head[x];i;i=q[i].nxt){ int dd=q[i].to; if(dd==fa) continue; dfs(dd,x);siz[x]+=siz[dd]; } } int lowbit(int x){return x&-x;} void change(int x,int v){ while(x<=N-10){ c[x]+=v;x+=lowbit(x); }return; } int qq(int x){ int res=0; while(x){ res+=c[x];x-=lowbit(x); }return res; } bool cmp1(query A,query B){ return A.l<B.l; } bool cmp2(query A,query B){ return A.r<B.r; } bool cmp3(query A,query B){ return A.id<B.id; } signed main(){ ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); cin >> n; for(int i=1;i<=n;i++){ cin >> v[i];b[i]=v[i]; }sort(b+1,b+n+1); int tt=unique(b+1,b+n+1)-b-1; for(int i=1;i<=n;i++){ v[i]=lower_bound(b+1,b+tt+1,v[i])-b; //cout << v[i] << "--\n"; } for(int i=2;i<=n;i++){ int x;cin >> x; add(x,i),add(i,x); } dfs(1,0); for(int i=1;i<=n;i++){ e[i]={i,dfn[i],dfn[i]+siz[i]-1,v[i],0}; //cout << e[i].l <<' '<< e[i].r <<' '<< e[i].x << '\n'; }sort(e+1,e+n+1,cmp1); for(int i=1;i<=n;i++){ e[i].ans-=(qq(n)-qq(e[i].x)); change(e[i].x,1);tmp[i]=e[i]; }sort(e+1,e+n+1,cmp2);int pos=0; memset(c,0,sizeof c); for(int i=1;i<=n;i++){ while(pos!=e[i].r){ pos++;change(tmp[pos].x,1); }e[i].ans+=(qq(n)-qq(e[i].x)); }sort(e+1,e+n+1,cmp3); for(int i=1;i<=n;i++){ cout << e[i].ans << '\n'; } return 0; } -
- 1
信息
- ID
- 85
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- (无)
- 递交数
- 14
- 已通过
- 8
- 上传者