题解 P5290 【[十二省联考2019]春节十二响】

_虹_

2019-04-08 17:23:02

Solution

~~D2唯一看懂的题~~ ~~而且考场上没看懂为啥1可能不是链端点~~ ~~大力观察题意~~,这题可以贪心,直接合并子节点的priority_queue,上界n^2logn,虽然上界很松,还是怂了。 可以发现两个序列合并后,序列依然是有序的,没有必要用排序,所以可以直接用vector维护。 ~~然后随机数据考场电脑随便跑~~ ~~然后就没写启发式合并变成60分~~ 加上启发式合并就过了QAQ。。。。 下面是比较暴力的vector做法: ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; #define reg register typedef long long vt; const int kmaxn=200000+5; struct edge { int d; edge* nxt; }; edge mempool[kmaxn]; int mpt; edge* head[kmaxn]; void add_edge(int s,int d) { mempool[mpt].nxt=head[s]; head[s]=&mempool[mpt++]; head[s]->d=d; } vector<vt> q[kmaxn]; vt value[kmaxn]; int pos[kmaxn]; void merge(int& a,int& b) { if(a==0) { a=b; return; } if(q[a].size()<q[b].size()) { swap(a,b); } vt t=0; reg int i=0,L=min(q[a].size(),q[b].size()); for(i=0;i<L;++i) { t=max(q[a][i],q[b][i]); q[a][i]=t; } for(L=q[b].size();i<L;++i) { q[a].push_back(q[b][i]); } vector<vt> vec; swap(vec,q[b]); } int lb(int num) { vt v=value[num]; num=pos[num]; reg int l=0,r=q[num].size(); reg int mid=0,ans=0; if(q[num].empty()||q[num][0]<=v) return 0; else if(q[num].back()>v) return r; while(l<r) { mid=(l+r)>>1; if(q[num][mid]<=v) { r=mid; ans=mid; } else { l=mid+1; } } return ans; } void dfs(int now) { edge* t=head[now]; while(t) { dfs(t->d); merge(pos[now],pos[t->d]); t=t->nxt; } if(!head[now]) { pos[now]=now; } /* reg int p=pos[now]; for(reg int i=0,j=q[p].size();i<j;++i) { if(q[p][i]<=value[now]) { q[p].insert(q[p].begin()+i,value[now]); return; } } q[p].push_back(value[now]);*///链会超时 q[pos[now]].insert(q[pos[now]].begin()+lb(now),value[now]); } int n; int fa; int main() { ios::sync_with_stdio(false); cin>>n; for(reg int i=1;i<=n;++i){ cin>>value[i]; } for(reg int i=2;i<=n;++i) { cin>>fa; add_edge(fa,i); } dfs(1); vt ans=0; for(reg int i=q[pos[1]].size()-1;i>=0;--i) { ans+=q[pos[1]][i]; } cout<<ans<<endl; return 0; } ``` vector做法依然可以卡,因为对序列插入每个节点权值时,上界依旧是n,不过平衡树中序遍历+启发式合并就卡不掉了 ~~但是vector能过写什么平衡树~~ ~~依旧偷懒,记吃不记打~~