BZOJ4919 大根堆(動態規劃+線段樹合並/treap+啟發式合並)
阿新 • • 發佈:2018-12-01
freopen style 隊列優化 unique 單調隊列 bsp 動態規劃 lis names
一個顯然的dp是設f[i][j]為i子樹內權值<=j時的答案,則f[i][j]=Σf[son][j],f[i][a[i]~n]++。這樣是可以線段樹合並的,將各兒子加起來然後打上加法標記即可。需要標記永久化。
另一種做法是考慮擴展經典的單調隊列優化LIS的做法,維護子樹內答案為k時最小的最大值,用平衡樹維護,在父親處啟發式合並,然後將父親處權值插入即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 200010 #define lson tree[k].ch[0] #define rson tree[k].ch[1] char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);}int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,a[N],b[N],fa[N],p[N],root[N],t,cnt; struct data{int to,nxt; }edge[N<<1]; structdata2{int x,p,ch[2],s; }tree[N<<5]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void up(int k){tree[k].s=tree[lson].s+tree[rson].s+1;} void move(int &k,int p) { int t=tree[k].ch[p]; tree[k].ch[p]=tree[t].ch[!p],tree[t].ch[!p]=k,up(k),up(t),k=t; } void ins(int &k,int x) { if (k==0) {k=++cnt;tree[k].x=x,tree[k].p=rand(),tree[k].s=1;return;} tree[k].s++; if (tree[k].x<x) {ins(rson,x);if (tree[rson].p>tree[k].p) move(k,1);} else {ins(lson,x);if (tree[lson].p>tree[k].p) move(k,0);} } void del(int &k,int x) { if (tree[k].x==x) { if (lson==0||rson==0) {k=lson|rson;return;} if (tree[lson].p>tree[rson].p) move(k,0),del(rson,x); else move(k,1),del(lson,x); } else if (tree[k].x<x) del(rson,x); else del(lson,x); up(k); } int qrank(int k,int x) { if (!k) return 0; if (tree[k].x>=x) return qrank(lson,x); else return qrank(rson,x)+tree[lson].s+1; } int find(int k,int x) { if (tree[lson].s+1==x) return tree[k].x; if (tree[lson].s+1>x) return find(lson,x); else return find(rson,x-tree[lson].s-1); } void dfsins(int k,int &x) { if (!k) return; ins(x,tree[k].x); dfsins(lson,x),dfsins(rson,x); } int merge(int x,int y) { if (tree[x].s<tree[y].s) swap(x,y); dfsins(y,x); return x; } void dfs(int k) { for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=fa[k]) { dfs(edge[i].to); root[k]=merge(root[k],root[edge[i].to]); } int x=qrank(root[k],a[k]); if (x<tree[root[k]].s) del(root[k],find(root[k],x+1)); ins(root[k],a[k]); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4919.in","r",stdin); freopen("bzoj4919.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read();srand(20020509); for (int i=1;i<=n;i++) { b[i]=a[i]=read(),fa[i]=read(); addedge(fa[i],i); } sort(b+1,b+n+1); int u=unique(b+1,b+n+1)-b-1; for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+u+1,a[i])-b; dfs(1); cout<<tree[root[1]].s; return 0; }
BZOJ4919 大根堆(動態規劃+線段樹合並/treap+啟發式合並)