BZOJ(本校) 3049 第K大 - 二分&树形dp
来源:互联网 发布:rlcf pic单片机指令 编辑:程序博客网 时间:2024/06/11 11:49
【问题描述】
给出一棵N个节点的树,每个节点上有一个正整数权值。给定K。
每条路径都有某个确定的第K大的节点权值,如果路径上点数比K小则规定第K大权值为0。现在有一个问题是,在这棵树里总共O(N^2)条路径,他们所有的第K大节点权值中,最大的那个是多少?
然后还有一个问题。这个问题总共有Q个询问,每次询问格式如下:“假如我把原树中编号为pi的节点权值增加vi,那么最初那个问题的答案会是多少?”规定所有Q个询问中pi都会在给定的某M个节点里面。
【输入格式】
第一行四个数N、K、M、Q。节点从1开始编号。
第二行N个数vi,表示第i个节点的权值。
第三行M个数pi,表示M个选定点。
接下来N-1行每行两个数ui,vi,ui和vi有一条边。
接下来Q行每行两个数pi,vi,表示把节点pi的权值增加vi。这里的pi保证是上面所规定的M个节点里面的一个。
【输出格式】
第一行输出一个数,表示第一问的答案。
接下来Q行每行输出一个数,表示第i个询问的答案。
【输入输出样例1】
6 4 2 0
4 3 5 2 6 1
2 4
1 2
1 3
1 4
1 5
1 6
///
0
【样例解释1】
无论你怎么选择路径,长度最多为3,K=4,所以答案为0。
【输入输出样例2】
12 3 3 5
1 2 3 4 5 6 7 8 9 10 11 12
8 5 7
1 8
8 3
8 11
1 5
5 9
5 2
5 12
1 7
7 4
4 6
4 10
8 1
5 2
7 3
8 4
5 5
///
8
9
8
10
11
10
【样例解释2】
按输出顺序的其中一种选择路径方案如下:11~10;11~10;11~10;12~10;11~12;11~12。
【数据规模】
所有数据均为不超过10^6的正整数。M<=5。
maxN maxK maxQ
1 50 50 50
2 100000 2 100000
3 100 100 100
4 200 200 200
5 300 5 300
6 500 500 100
7~10 100000 100000 100000
注意:本题设置部分分。如果第一行输出正确则得到50%该测试点的分;如果最后的Q行输出均正确则得到另外50%的分。
分析:
- 第一问:二分+dp判定
二分最大的第k大的数mid,dp找路径上的点权大于等于mid的最多的点的个数,如果这个个数大于等于k,mid合法;小于k,mid不合法。 - 第二问:注意到M<=5,且修改不具有后效性。
找到经过要修改的点x的所有路径,如果x增加权值能改变第一问的ans,那么w[x]<=ans&&w[x]+delta_w>ans,而且新的答案只能用w[x]+delta_w或者以前除了w[x]的第k-1大的元素权值来更新。 - 总时间复杂度O(M*nlogn)
#include<cstdio>#include<algorithm>using namespace std;#define MAXN 100000struct node{ int v; node *next;}edge[MAXN*2+10],*adj[MAXN+10],*ecnt=&edge[0];int n,m,k,ans,b[MAXN+10],w[MAXN+10],f[MAXN+10][2],mx,t,a[MAXN+10],Q;void addedge(int u,int v){ node *p=++ecnt; p->v=v; p->next=adj[u]; adj[u]=p;}void read(){ int x,y; scanf("%d%d%d%d",&n,&k,&m,&Q); for(int i=1;i<=n;i++){ scanf("%d",&w[i]); mx=max(mx,w[i]); } for(int i=1;i<=m;i++) scanf("%d",&a[i]); for(int i=1;i<n;i++){ scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); }}void DP(int u,int fa,int lmt){ f[u][0]=f[u][1]=0; for(node *p=adj[u];p;p=p->next){ if(p->v==fa) continue; DP(p->v,u,lmt); if(f[u][0]<=f[p->v][0]){ f[u][1]=f[u][0]; f[u][0]=f[p->v][0]; } else if(f[u][1]<f[p->v][0]) f[u][1]=f[p->v][0]; } if(w[u]>=lmt) f[u][0]++; f[u][1]+=f[u][0]; t=max(t,f[u][1]);}void Quary1(){ int l=1,r=mx,mid; while(l<=r){ mid=(l+r)/2; t=0; //一条路径上最大的点权大于mid的点数 DP(1,0,mid); if(t<k) r=mid-1; else l=mid+1,ans=mid; }}void Quary2() //M*nlogn{ for(int i=1,tmp;i<=m;i++){ tmp=w[a[i]],w[a[i]]=-1; int l=1,r=mx,mid; while(l<=r){ //找到在经过a[i]的路径中,除了w[a[i]]的第k-1大 mid=(l+r)/2; DP(a[i],0,mid); if(f[a[i]][1]<k-1) r=mid-1; else l=mid+1,b[a[i]]=mid; } w[a[i]]=tmp; }}int main(){ int p,v; read(); Quary1(); printf("%d\n",ans); Quary2(); while(Q--){ scanf("%d%d",&p,&v); if(w[p]+v<=ans||w[p]>ans) //只有之前小于ans的w加上v之后大于ans,才会可能有答案的更新 printf("%d\n",ans); else printf("%d\n",max(ans,min(w[p]+v,b[p]))); //max(原来的第k大,修改后的可能第k大) }}
- BZOJ(本校) 3049 第K大 - 二分&树形dp
- BZOJ(本校) 3044 旅行 - 树形dp&基环树
- BZOJ(本校) 2665 密码锁 - 思维&dp
- BZOJ(本校) 3048 染色 - dp&递推找规律
- BZOJ(本校) 3027 快速傅里叶变换 - 概率与期望&dp
- BZOJ 2097 Exercise 奶牛健美操 二分答案+树形DP+贪心
- BZOJ 2067 POI 2004 SZN 树形DP 贪心 二分答案
- bzoj 4753: [Jsoi2016]最佳团体 二分答案+树形dp
- BZOJ 1901 动态第K大
- 二分 51Nod1686 第K大区间
- 51nod1686 第K大区间 【二分】
- bzoj 3611: [Heoi2014]大工程 虚树+树形dp
- 【BZOJ 3611】[Heoi2014]大工程 虚树+树形dp
- bzoj 3611: [Heoi2014]大工程 (虚树+树形DP)
- bzoj 3611: [Heoi2014]大工程(虚树+树形DP)
- BZOJ 2152 (树形DP)
- bzoj 3037(树形DP)
- bzoj 4027 树形dp
- HDFS小文件问题及解决方案
- linux常用的20条命令
- RecyclerView点滴
- VC 窗口创建以及窗口之间传递数据、传递消息(模态、非模态)
- 关于UISearchController的使用方法
- BZOJ(本校) 3049 第K大 - 二分&树形dp
- 批量插入 insert 可以
- 判断是否可以打电话(有无SIM卡、是否飞行模式、信号是否良好)
- Linux系统管理员不可不知的命令:sudo
- php rsa加密解密使用详解
- 利用doker快速搭建node.js运行环境
- NGINX重启HTTPS站点要Enter PEM pass phrase输入密码
- 五子棋AI算法第七篇-Zobrist
- 程序员的十层楼