卧薪尝胆,厚积薄发。
USACO2017JAN PLATINUM Promotion Counting
Date: Tue Sep 18 08:31:30 CST 2018
In Category:
NoCategory
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:
数据结构-线段树合并
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡