ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[luogu8341]回忆

2022-05-19 08:35:40  阅读:125  来源: 互联网

标签:标记 int max sum 路径 luogu8341 mx 回忆


考虑将所有极深的$t$配对,表示选择对应的路径(要求经过$1$)

具体的,假设$1$的儿子子树内分别有$a_{1},a_{2},...,a_{k}$个$t$,对其分类讨论:

1.若$2\max a_{i}\le \sum a_{i}$,则可以配成$\lceil\frac{\sum a_{i}}{2}\rceil$对(归纳证明),且取到答案下限

2.若$2\max a_{i}>\sum a_{i}$,则可以配成$\sum a_{i}-\max a_{i}$对,且仅需考虑$\max a_{i}$对应子树的子问题

关于这个子问题,与原问题相比有以下不同:

1.可以"免费"选择$\sum a_{i}-\max a_{i}$条"直路径"(端点构成祖先-后代关系)

2.需处理$s_{i}=1$且$t_{i}$在该子树内的限制,具体如下——

(1)若其子树内存在标记,则该限制已经满足,跳过即可

(2)若其某个祖先存在标记,取该祖先(必然唯一),将该标记删除

(3)若存在"免费"的"直路径",则将其数量减1,否则将答案加1

(4)对于第(2)和(3)种,在$t_{i}$上打一个标记,表示可以"免费"选择经过$t_{i}$的"直路径"

在此基础上,需要将$a_{i}$减去子树内标记数,判定条件中将$\max a_{i}$和$\sum a_{i}$均减去1.的数量

可以使用树状数组维护(找祖先求和即可),时间复杂度为$o(n\log n)$,可以通过

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 200005
  4 int t,n,m,x,y,tag,ans,dfn[N],sz[N],a[N],f[N],sum[N],cnt[N],Tag[N];
  5 vector<int>e[N],v[N];
  6 int read(){
  7     int x=0;char c=getchar();
  8     while ((c<'0')||(c>'9'))c=getchar();
  9     while ((c>='0')&&(c<='9'))x=x*10+c-'0',c=getchar();
 10     return x;
 11 }
 12 int lowbit(int k){
 13     return (k&(-k));
 14 }
 15 void update(int k,int x){
 16     while (k<=n)f[k]+=x,k+=lowbit(k);
 17 }
 18 int query(int k){
 19     int ans=0;
 20     while (k)ans+=f[k],k^=lowbit(k);
 21     return ans;
 22 }
 23 void Update(int k,int x){
 24     while (k<=n)sum[k]+=x,k+=lowbit(k);
 25 }
 26 int Query(int k){
 27     int ans=0;
 28     while (k)ans+=sum[k],k^=lowbit(k);
 29     return ans;
 30 }
 31 void add(int k){
 32     Tag[k]++,update(dfn[k],1);
 33     Update(dfn[k],k),Update(dfn[k]+sz[k],-k);
 34 }
 35 void dec(int k){
 36     Tag[k]--,update(dfn[k],-1);
 37     Update(dfn[k],-k),Update(dfn[k]+sz[k],k);
 38 }
 39 bool cmp(int x,int y){
 40     return dfn[x]<dfn[y];
 41 }
 42 void dfs(int k,int fa){
 43     dfn[k]=++dfn[0],sz[k]=1;
 44     for(int i:e[k])
 45         if (i!=fa)dfs(i,k),sz[k]+=sz[i];
 46 }
 47 void get_cnt(int k,int fa){
 48     for(int i:e[k])
 49         if (i!=fa)get_cnt(i,k),cnt[k]+=cnt[i];
 50 }
 51 void calc(int k,int fa){
 52     if (Tag[k])tag++,dec(k);
 53     int s=0,mx=0,son;
 54     for(int i:e[k])
 55         if (i!=fa){
 56             a[i]=cnt[i]-(query(dfn[i]+sz[i]-1)-query(dfn[i]-1));
 57             s+=a[i],mx=max(mx,a[i]);
 58         }
 59     if (s<=tag)return; 
 60     if ((mx-tag<<1)<=s-tag){
 61         ans+=(s-tag+1>>1);
 62         return;
 63     }
 64     tag+=s-mx,ans+=s-mx;
 65     for(int i:e[k])
 66         if ((i!=fa)&&(a[i]==mx)){
 67             son=i;
 68             break;
 69         }
 70     for(int i:v[k])
 71         if ((dfn[son]<=dfn[i])&&(dfn[i]<dfn[son]+sz[son])){
 72             if (query(dfn[i]-1)<query(dfn[i]+sz[i]-1))continue;
 73             int pos=Query(dfn[i]);
 74             if (pos)dec(pos);
 75             else{
 76                 if (tag)tag--;else ans++;
 77             }
 78             add(i);
 79         }
 80     calc(son,k); 
 81 }
 82 int main(){
 83     t=read();
 84     while (t--){
 85         n=read(),m=read();
 86         tag=ans=dfn[0]=0;
 87         for(int i=1;i<=n;i++){
 88             f[i]=sum[i]=cnt[i]=Tag[i]=0;
 89             e[i].clear(),v[i].clear();
 90         }
 91         for(int i=1;i<n;i++){
 92             x=read(),y=read();
 93             e[x].push_back(y),e[y].push_back(x);
 94         }
 95         for(int i=1;i<=m;i++){
 96             x=read(),y=read();
 97             a[i]=y,v[x].push_back(y);
 98         }
 99         dfs(1,0),sort(a+1,a+m+1,cmp);
100         for(int i=m;i;i--){
101             int k=a[i];
102             if (query(dfn[k]-1)==query(dfn[k]+sz[k]-1))cnt[k]=1;
103             update(dfn[k],1);
104         }
105         for(int i=1;i<=n;i++)f[i]=0;
106         get_cnt(1,0),calc(1,0),printf("%d\n",ans);
107     }
108     return 0;
109 }
View Code

 

标签:标记,int,max,sum,路径,luogu8341,mx,回忆
来源: https://www.cnblogs.com/PYWBKTDA/p/16287156.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有