bzoj4919 大根堆(線段樹合併)
阿新 • • 發佈:2019-02-19
也是雅禮集訓考的一題。。。
似乎不必要用線段樹合併,用個set也能又好又快的水過去。。。
先考慮最簡單的樹形dp怎麼做;
設dp[i][j]表示當前在i節點並且選的最大不超過j的答案是多少;
考慮用動態開點的線段樹來維護dp陣列
對於每一個節點,只需要先把其兒子的dp陣列加起來,這就對應線段樹合併操作;又因為我用的標記永久化,每一次修改對應區間直接相加;
再根據自己本身的值進行略微修改就好;
先考慮每一次會怎麼修改,很顯然的是對於每一個dp陣列都是單調不降的。而又要從最大值進行轉移;
設當前點的值為v,那麼選這個點的貢獻則為dp[i][v-1]+1;
再考慮新新增的值怎麼加進線段樹中,那麼就要把v到maxv中所有比新貢獻小的進行修改;
而每次修改最多隻會加1(因為單調性嘛。。。
所以可以二分出需要修改的點,每一次二分都要一個log從線段樹裡查值,再加上線段樹合併的複雜度,總體還是n(logn)^2的
具體細節看程式碼
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
const int maxn=200005;
struct NODE{
int col,l,r;
}t[maxn*40];
int ntot=0;
int rt[maxn],nv[maxn],v[maxn],vtot=0,node[maxn];
void modify(int l,int r,int &x,int nl,int nr,int v)
{
if(!x)x=++ntot;
if(nl<=l&&nr>=r){
t[x].col+=v;
return;
}
int mid=(l+r)>>1;
if(nl<=mid)modify(l,mid,t[x].l,nl,nr,v);
if(nr>mid)modify(mid+1,r,t[x].r,nl,nr,v);
}
int query(int l,int r,int x,int pos){
if(!pos)return 0;
if(!x)return 0;
int tans=t[x].col;
int mid=(l+r)>>1;
if(pos<=mid)tans+=query(l,mid,t[x].l,pos);
else tans+=query(mid+1,r,t[x].r,pos);
return tans;
}
int merge(int x,int y){
if(!x||!y)return x+y;
t[x].col+=t[y].col;
t[x].l=merge(t[x].l,t[y].l);
t[x].r=merge(t[x].r,t[y].r);
return x;
}
struct EDGE{
int next,to;
}edge[maxn];
int etot=0;
void add(int x,int y){
edge[++etot].next=node[x];
edge[etot].to=y;
node[x]=etot;
}
void dfs(int x){
rt[x]=0;
for(int i=node[x];i;i=edge[i].next){
dfs(edge[i].to);
rt[x]=merge(rt[edge[i].to],rt[x]);
}
int mv=query(1,vtot,rt[x],nv[x]-1)+1;
if(mv<=query(1,vtot,rt[x],nv[x]))return;
int l=nv[x],r=vtot;
while(l<r){
int mid=((l+r)>>1)+((l+r)&1);
if(query(1,vtot,rt[x],mid)<mv)l=mid;
else r=mid-1;
}
modify(1,vtot,rt[x],nv[x],l,1);
}
int n=0;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
int tf;
scanf("%d%d",&nv[i],&tf);
add(tf,i);
v[++vtot]=nv[i];
}
std::sort(v+1,v+vtot+1);
vtot=std::unique(v+1,v+vtot+1)-v-1;
for(int i=1;i<=n;i++)nv[i]=std::lower_bound(v+1,v+vtot+1,nv[i])-v;
dfs(1);
printf("%d\n",query(1,vtot,rt[1],vtot));
return 0;
}
恩。。因為我的二分查值是實實在在的log^2,成功跑到bzoj rank 倒1;