ICode9

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

洛谷P5592 美德的讲坛

2021-01-06 10:04:20  阅读:159  来源: 互联网

标签:ch return val int siz 讲坛 P5592 solve 洛谷


对于 \(x\),存在 \(p\),满足 \(2^p \leqslant x < 2^{p+1}\),对于所有 \(a_i\) 按 \(\left\lfloor \frac{a_i}{2^p} \right\rfloor\) 的值分组,得每组内的两两异或值都 \(<x\)。

然后就只需考虑组与组之间的情况了,将其转化为最小割,源点向第一个组的每个点连容量为 \(1\) 的边,第二组的每个点向汇点连容量为 \(1\) 的边,两组间异或和 \(\geqslant x\) 的点对连容量为 \(\infty\) 的边。

直接跑最小割复杂度无法接受,先将最小割转为最大流,对所有权值建立 \(01\ Trie\)。

设 \(a_0\) 和 \(a_1\) 为 \(a\) 的左右子树,\(solve(a,b)\) 为以 \(a,b\) 为根的子树的最大匹配,得:

当 \(x\) 在对应深度为 \(1\) 时,得其值为 \(solve(a_0,b_1)+solve(a_1,b_0)\)。

当 \(x\) 在对应深度为 \(0\) 时,进行分类讨论:

\[\large\begin{aligned} &|a_0|<|b_1|\and|a_1|<|b_0| \Rightarrow |a| \\ &|a_0|>|b_1|\and|a_1|>|b_0| \Rightarrow |b| \\ &|a_0|>|b_1|\and|a_1|<|b_0| \Rightarrow \min(solve(a_0,b_0),|b_0|-|a_1|,|a_0|-|b_1|)+|a_1|+|b_1| \\ &|a_0|<|b_1|\and|a_1|>|b_0| \Rightarrow \min(solve(a_1,b_1),|b_1|-|a_0|,|a_1|-|b_0|)+|a_0|+|b_0| \end{aligned} \]

还需注意 \(a=b\) 的情况,设 \(v_0=solve(a_0,a_0),v_1=solve(a_1,a_1)\),其值为 \(v_0+v_1+\min(|a_0|-v_0,|a_1|-v_1)\)。

因为每次修改的节点个数为 \(O(\log n)\),所以每次询问记忆化即可。

#include<bits/stdc++.h>
#define maxn 100010
#define maxm 10000010
#define s(x,k) siz[ch[x][k]]
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,q,tot=1,root=1;
ll lim;
int ch[maxm][3],siz[maxm],val[maxm],dep[maxm];
ll a[maxn];
bool vis[maxm];
void insert(ll x,int v)
{
    int p=root;
    siz[p]+=v,dep[p]=60;
    for(int i=60;i>=0;--i)
    {
        int c=(x>>i)&1;
        vis[p]=false;
        if(!ch[p][c]) ch[p][c]=++tot;
        siz[p=ch[p][c]]+=v,dep[p]=i-1;
    }
}
int solve(int x,int y)
{
    if(!siz[x]||!siz[y]) return 0;
    if(vis[x]&&vis[y]) return val[x];
    vis[x]=vis[y]=true;
    if(dep[x]==-1) return val[x]=min(siz[x],siz[y]);
    if((lim>>dep[x])&1) return val[x]=solve(ch[x][0],ch[y][1])+solve(ch[x][1],ch[y][0]);
    int v0=solve(ch[x][0],ch[y][0]),v1=solve(ch[x][1],ch[y][1]);
    if(x==y) return val[x]=v0+v1+min(s(x,0)-v0,s(x,1)-v1);
    if(s(x,0)<=s(y,1)&&s(x,1)<=s(y,0)) return val[x]=siz[x];
    if(s(x,0)>=s(y,1)&&s(x,1)>=s(y,0)) return val[x]=siz[y];
    if(s(x,0)>=s(y,1)&&s(x,1)<=s(y,0))
        return val[x]=min(v0,min(s(y,0)-s(x,1),s(x,0)-s(y,1)))+s(x,1)+s(y,1);
    if(s(x,0)<=s(y,1)&&s(x,1)>=s(y,0))
        return val[x]=min(v1,min(s(y,1)-s(x,0),s(x,1)-s(y,0)))+s(x,0)+s(y,0);
}
int main()
{
    read(n),read(q),read(lim);
    for(int i=1;i<=n;++i) read(a[i]),insert(a[i],1);
    printf("%d\n",max(n-solve(root,root),1));
    while(q--)
    {
        int x;
        read(x),insert(a[x],-1);
        read(a[x]),insert(a[x],1);
        printf("%d\n",max(n-solve(root,root),1));
    }   
    return 0;
}

标签:ch,return,val,int,siz,讲坛,P5592,solve,洛谷
来源: https://www.cnblogs.com/lhm-/p/14239364.html

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

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

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

ICode9版权所有