[APIO2012]派遣 洛谷P1552 bzoj2809 codevs1763

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 }
原文地址:https://www.cnblogs.com/hehe54321/p/9035162.html