• [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
  • 相关阅读:
    HDFS Namenode 高可用
    旁路模式,numa、mmu、调整内存分页大小
    k8s 调度 GPU
    破解 CSDN 登录后才能复制
    微信小程序开发video遮罩功能(禁止拖动进度条)
    微信小程序之下拉刷新
    微信小程序JS中文排序
    vue2 和 vue3 路由使用对比
    Golang 操作mongo
    win10安装CUDA和cuDNN的正确姿势
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/16287156.html
Copyright © 2020-2023  润新知