http://www.codevs.cn/problem/1763/
https://www.lydsy.com/JudgeOnline/problem.php?id=2809
https://www.luogu.org/problemnew/show/P1552
http://210.33.19.101/problem/2182
用线段树合并,值域线段树维护可重集合,线段树每个节点维护一个sum表示当前集合中,所有在范围[l,r](这个点的值域区间)内的数的和;每个点从其子节点合并;查询就根据左子节点sum与当前最大允许的和决定往左还是往右走
话说稍微有点卡空间。。。(加了内存回收,然而理论上内存回收应该并不能改进最坏空间复杂度)
看了题解,发现只要暴力启发式合并/可并堆,合并完成后暴力删除最大值直到合法就行了。。。(因为每个点只会被删一次)
又想了想,只要暴力普通堆启发式合并就行了。。。。40行就行。。。
1 #pragma GCC optimize(3)//不开优化可能被卡常 2 #include<cstdio> 3 #include<algorithm> 4 #include<queue> 5 #include<vector> 6 #define pb push_back 7 using namespace std; 8 typedef long long LL; 9 int n,m; 10 vector<int> ch[100100]; 11 int c[100100],l[100100],fa[100100]; 12 LL sum[100100]; 13 priority_queue<int> q[100100]; 14 LL ans; 15 void dfs(int u) 16 { 17 int i,v; 18 q[u].push(c[u]);sum[u]+=c[u]; 19 for(i=0;i<ch[u].size();i++) 20 { 21 v=ch[u][i]; 22 dfs(v); 23 if(q[v].size()>q[u].size()) swap(q[u],q[v]); 24 while(!q[v].empty()) q[u].push(q[v].top()),q[v].pop(); 25 sum[u]+=sum[v]; 26 } 27 while(sum[u]>m) sum[u]-=q[u].top(),q[u].pop(); 28 ans=max(ans,l[u]*LL(q[u].size())); 29 } 30 int main() 31 { 32 int i,a; 33 scanf("%d%d",&n,&m); 34 for(i=1;i<=n;i++) 35 { 36 scanf("%d%d%d",&a,&c[i],&l[i]); 37 fa[i]=a;ch[a].pb(i); 38 } 39 dfs(1); 40 printf("%lld",ans); 41 return 0; 42 }
空间因为pq里面用了vector之类的好像会被卡。。。可以改一下
1 #pragma GCC optimize(3)//不开优化可能被卡常 2 #include<cstdio> 3 #include<algorithm> 4 #include<queue> 5 #include<vector> 6 #define pb push_back 7 using namespace std; 8 typedef long long LL; 9 int n,m; 10 vector<int> ch[100100]; 11 int c[100100],l[100100],fa[100100]; 12 LL sum[100100]; 13 priority_queue<int> *q[100100]; 14 LL ans; 15 void dfs(int u) 16 { 17 int i,v;q[u]=new priority_queue<int>(); 18 q[u]->push(c[u]);sum[u]+=c[u]; 19 for(i=0;i<ch[u].size();i++) 20 { 21 v=ch[u][i]; 22 dfs(v); 23 if(q[v]->size()>q[u]->size()) swap(q[u],q[v]); 24 while(!q[v]->empty()) q[u]->push(q[v]->top()),q[v]->pop(); 25 sum[u]+=sum[v];delete q[v]; 26 } 27 while(sum[u]>m) sum[u]-=q[u]->top(),q[u]->pop(); 28 ans=max(ans,l[u]*LL(q[u]->size())); 29 } 30 int main() 31 { 32 int i,a; 33 scanf("%d%d",&n,&m); 34 for(i=1;i<=n;i++) 35 { 36 scanf("%d%d%d",&a,&c[i],&l[i]); 37 fa[i]=a;ch[a].pb(i); 38 } 39 dfs(1); 40 printf("%lld",ans); 41 return 0; 42 }
错误记录:答案没有开longlong所以无限WA
1 #include<cstdio> 2 #include<algorithm> 3 #include<vector> 4 #define pb push_back 5 using namespace std; 6 typedef long long LL; 7 namespace S 8 { 9 #define mid (l+((r-l)>>1)) 10 #define N 3000000 11 int dat[N],lc[N],rc[N];LL sum[N]; 12 int L; 13 int st[N+100],top; 14 void init() 15 { 16 int i; 17 for(i=1;i<N;i++) st[++top]=i; 18 } 19 int getnode() 20 { 21 int t=st[top--];dat[t]=sum[t]=lc[t]=rc[t]=0; 22 return t; 23 } 24 void delnode(int x) {st[++top]=x;} 25 void _addx(int l,int r,int &num) 26 { 27 if(!num) num=getnode(); 28 if(l==r) {dat[num]++;sum[num]+=l;return;} 29 if(L<=mid) _addx(l,mid,lc[num]); 30 else _addx(mid+1,r,rc[num]); 31 dat[num]=dat[lc[num]]+dat[rc[num]]; 32 sum[num]=sum[lc[num]]+sum[rc[num]]; 33 } 34 void addx(int p,int &num) 35 { 36 L=p;_addx(1,1e9,num); 37 } 38 int merge(int a,int b) 39 { 40 if(!a||!b) return a+b; 41 lc[a]=merge(lc[a],lc[b]); 42 rc[a]=merge(rc[a],rc[b]); 43 dat[a]+=dat[b]; 44 sum[a]+=sum[b]; 45 delnode(b); 46 return a; 47 } 48 int find(int l,int r,int num,LL msum) 49 { 50 if(l==r) return msum/l; 51 if(sum[lc[num]]>=msum) return find(l,mid,lc[num],msum); 52 else return find(mid+1,r,rc[num],msum-sum[lc[num]])+dat[lc[num]]; 53 } 54 #undef mid 55 } 56 vector<int> ch[200100]; 57 int n,m; 58 int c[200100],l[200100],fa[200100]; 59 int rt[200100];LL ans; 60 void dfs(int u) 61 { 62 S::addx(c[u],rt[u]); 63 for(int i=0,v;i<ch[u].size();i++) 64 { 65 v=ch[u][i]; 66 dfs(v); 67 rt[u]=S::merge(rt[u],rt[v]); 68 } 69 ans=max(ans,LL(l[u])*S::find(1,1e9,rt[u],m)); 70 } 71 int main() 72 { 73 int i,a;S::init(); 74 scanf("%d%d",&n,&m); 75 for(i=1;i<=n;i++) 76 { 77 scanf("%d%d%d",&a,&c[i],&l[i]); 78 fa[i]=a;ch[a].pb(i); 79 } 80 dfs(1); 81 printf("%lld",ans); 82 return 0; 83 }