卧薪尝胆,厚积薄发。
      
    
            USACO2017JAN PLATINUM Promotion Counting
        
        
        Description:
给一棵树,每个节点有权值,问每个点子树中有多少点权值比他大。
$1\le n \le 100000$
Solution:
线段树合并,每次把子节点的线段树合并到自己这里,然后查一个后缀和。
听说时间复杂度
$O(n\log n)$
。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#include<cstring>
using namespace std;
inline int read()
{
	register int res = 0;
	register char c = getchar();
	while(!isdigit(c))c = getchar();
	while(isdigit(c))
	{
		res = (res << 1) + (res << 3) + c - '0';
		c = getchar();
	}
	return res;
}
int n;
#define MAXN 100010
int val[MAXN];
int b[MAXN];
map<int,int> fr;
int tot = 0;
struct edge
{
	int to,nxt;
}e[MAXN];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
	++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
	return;
}
struct node
{
	int lc,rc;
	int sum;
}t[MAXN * 30];
int ptr = 0;
int newnode(){return ++ptr;}
int root[MAXN];
#define mid ((l + r) >> 1)
void insert(int &rt,int p,int l,int r)
{
	if(rt == 0)rt = newnode();
	++t[rt].sum;
	if(l == r)return;
	if(p <= mid)insert(t[rt].lc,p,l,mid);
	else insert(t[rt].rc,p,mid + 1,r);
	return;
}
int merge(int x,int y)
{
	if(!x)return y;if(!y)return x;
	t[x].lc = merge(t[x].lc,t[y].lc);
	t[x].rc = merge(t[x].rc,t[y].rc);
	t[x].sum = t[x].sum + t[y].sum;
	return x;
}
int query(int rt,int L,int R,int l,int r)
{
	if(L > R)return 0;
	if(L <= l && r <= R)return t[rt].sum;
	int res = 0;
	if(L <= mid)res += query(t[rt].lc,L,R,l,mid);
	if(R > mid)res += query(t[rt].rc,L,R,mid + 1,r);
	return res;
}
int ans[MAXN];
void dfs(int k)
{
	for(int i = lin[k];i != 0;i = e[i].nxt)
	{
		dfs(e[i].to);
		root[k] = merge(root[k],root[e[i].to]);
	}
	ans[k] = query(root[k],val[k] + 1,tot,1,tot);
	return;
}
int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)val[i] = read();
	for(int i = 1;i <= n;++i)b[i] = val[i];
	sort(b + 1,b + 1 + n);
	for(int i = 1;i <= n;++i)
		if(i == 1 || b[i] != b[i - 1])
			fr[b[i]] = ++tot;
	for(int i = 1;i <= n;++i)val[i] = fr[val[i]];
	for(int i = 2;i <= n;++i)add(read(),i);
	for(int i = 1;i <= n;++i)insert(root[i],val[i],1,tot);
	dfs(1);
	for(int i = 1;i <= n;++i)printf("%d\n",ans[i]);
	return 0;
}
 In tag:
数据结构-线段树合并
          In tag:
数据结构-线段树合并 
          
        
        Copyright © 2020
        
          wjh15101051
        
      
      ღゝ◡╹)ノ♡
     Date: Tue Sep 18 08:31:30 CST 2018
          Date: Tue Sep 18 08:31:30 CST 2018
           In Category:
          In Category:
           
         Timeline
            Timeline
           About
            About
           Toolbox
            Toolbox
           Friends
              Friends