[luogu8341]回忆
作者:互联网
考虑将所有极深的$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