[CTSC2008] 网络管理

探讨了在树结构中查询第K大元素的两种高效算法。一种利用树剖、线段树和平衡树实现,复杂度为O(nlog^4n);另一种通过DFS序结合树状数组和主席树,复杂度降低至O(nlog^2n)。详细解释了算法原理及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

带修树链第K大。\((n,q\leq 80000)\)

Solution

据说有很多种方法?
写了两种。

  1. 树剖套线段树套平衡树,外层还需要个二分,复杂度\(O(n\log^4n)\)
  2. \(dfs\)序上维护树状数组套主席树,复杂度\(O(n\log^2n)\)

第一种就是比较裸的树套树吧,注意二分的\(check(x)\)定义是当答案为\(x\)时这条链上是否有至少\(k\)个大于\(x\)的点。
然后平衡树上查就行了。
试了几个\(srand\)发现我的生日加上xxx的生日跑的最快...
第二种就可以说一说了
先考虑无修改树链第\(k\)大怎么求,显然每个点的主席树存下了这个点到根的路径上所有点的权值。然后就是\(sum[x]+sum[y]-sum[lca(x,y)]-sum[fa[lca(x,y)]]\)
如果有修改,那么改一个点时会影响到子树内的\(O(n)\)棵主席树。
但是观察到一个点的子树的\(dfs\)序是一段区间,可以区间加这个玩意儿。
然而区间主席树加某个值并不好加,我们可以在差分序列上变成单点加。然后求和的时候求一个前缀和就行了。具体地,我们可以把求这四个点(\(x,y,lca(x,y),fa[lca(x,y)]\))的前缀和所需要用到的点都存进一个数组里面,然后主席树求\(k\)大的时候就不是四个点同时往下走而是这个数组里面所有的点同时往下走了。
然后要记得输出原本的值不要输出离散化之后的值。。。
别的就没啥了,发现自己已经zz到看一个单点加都要思考半天为什么要用树状数组了。。。。

Code

\(O(n\log^4n)\)代码
这奇怪的变量名奇怪的函数名和奇怪的缩进是我想写namespace无果造成的,我的码风还是正常的你们要相信我啊喂

#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
const int N=80005;
typedef double db;
typedef long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define mp(A,B) std::make_pair(A,B)

int root[N<<2];
int head[N],dfn[N],val[N];
int n,m,cnt,fa[N],d[N],tot;
int top[N],sze[N],son[N],fs[N];

struct Edge{
    int to,nxt;
}edge[N<<1];

void add(int x,int y){
    edge[++cnt].to=y;
    edge[cnt].nxt=head[x];
    head[x]=cnt;
}

    int ttot;
    int delpool[N*20],delcur;
    int tsze[N*20],tprio[N*20];
    int tch[N*20][2],tval[N*20];

    void tpushup(int cur){
        tsze[cur]=tsze[tch[cur][0]]+tsze[tch[cur][1]]+1;
    }

    void trotate(int &x,int d){
        int y=tch[x][d],z=tch[y][d^1];
        tch[y][d^1]=x;tch[x][d]=z;
        tpushup(x);tpushup(y);x=y;
    }

    int newnode(){
        int t=delcur?delpool[delcur--]:++ttot;
        tch[t][0]=tch[t][1]=tval[t]=tprio[t]=tsze[t]=0;return t;
    }

    void tinsert(int &cur,int x){
        if(!cur){
            cur=newnode();
            tsze[cur]=1;tval[cur]=x;tprio[cur]=rand();
            return;
        }
        int d=x>tval[cur];
        tsze[cur]++;
        tinsert(tch[cur][d],x);
        if(tprio[tch[cur][d]]<tprio[cur])
            trotate(cur,d);
    }

    void tremove(int &cur,int x){
        if(tval[cur]==x){
            if(!tch[cur][0] or !tch[cur][1]){
                delpool[++delcur]=cur;
                cur=tch[cur][0]+tch[cur][1];
                return;
            }
            if(tprio[tch[cur][0]]<tprio[tch[cur][1]])
                trotate(cur,0),tremove(tch[cur][1],x);
            else trotate(cur,1),tremove(tch[cur][0],x);
            tpushup(cur);
        } else{
            int d=x>tval[cur];
            tremove(tch[cur][d],x);
            tpushup(cur);
        }
    }

    int trank(int cur,int x){
        if(!cur) return 0;
        if(tval[cur]>=x) return tsze[tch[cur][1]]+1+trank(tch[cur][0],x);
        else return trank(tch[cur][1],x);
    }

    void dfs(int x,int y){
        if(!x) return;
        tinsert(root[y],tval[x]);
        dfs(tch[x][0],y);
        dfs(tch[x][1],y);
    }

    void build(int cur,int l,int r){
        if(l==r){
            tinsert(root[cur],val[fs[l]]);
            return;
        }
        int mid=l+r>>1;
        build(cur<<1,l,mid);build(cur<<1|1,mid+1,r);
        dfs(root[cur<<1],cur);dfs(root[cur<<1|1],cur);
    }

    void modify(int cur,int l,int r,int ql,int qr,int minus,int add){
        tremove(root[cur],minus);tinsert(root[cur],add);
        if(l==r) return;
        int mid=l+r>>1;
        if(ql<=mid) modify(cur<<1,l,mid,ql,qr,minus,add);
        else modify(cur<<1|1,mid+1,r,ql,qr,minus,add);
    }

    int query(int cur,int l,int r,int ql,int qr,int c){
        if(ql<=l and r<=qr)
            return trank(root[cur],c);
        int mid=l+r>>1,ans=0;
        if(ql<=mid) ans+=query(cur<<1,l,mid,ql,qr,c);
        if(mid<qr) ans+=query(cur<<1|1,mid+1,r,ql,qr,c);
        return ans;
    }

int getint(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch))w|=ch=='-',ch=getchar();
    while( isdigit(ch))X=X*10+ch-48,ch=getchar();
    return w?-X:X;
}

void dfs1(int now){
    sze[now]=1;
    for(int i=head[now];i;i=edge[i].nxt){
        int to=edge[i].to;
        if(sze[to]) continue;
        fa[to]=now;d[to]=d[now]+1;
        dfs1(to);sze[now]+=sze[to];
        son[now]=sze[to]>sze[son[now]]?to:son[now];
    }
}

void dfs2(int now,int low){
    dfn[now]=++tot;top[now]=low;fs[tot]=now;
    if(son[now]) dfs2(son[now],low);
    for(int i=head[now];i;i=edge[i].nxt){
        int to=edge[i].to;
        if(dfn[to]) continue;
        dfs2(to,to);
    }
}

bool check(int mid,int k,int x,int y){
    int ans=0,fir=d[x]+d[y];
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]])
            swap(x,y);
        ans+=query(1,1,n,dfn[top[x]],dfn[x],mid);
        x=fa[top[x]];
    }
    if(d[x]<d[y]) swap(x,y);
    ans+=query(1,1,n,dfn[y],dfn[x],mid);
    fir-=d[y]*2;fir++;
    if(fir<k) return 0;
    if(ans>=k) return 1;
    return 0;
}

signed main(){
    srand(20020122);
    n=getint(),m=getint();
    for(int i=1;i<=n;i++)
        val[i]=getint();
    for(int i=1;i<n;i++){
        int x=getint(),y=getint();
        add(x,y);add(y,x);
    }
    d[1]=1;dfs1(1);dfs2(1,1);build(1,1,n);
    while(m--){
        int k=getint(),x=getint(),y=getint();
        if(!k){
            modify(1,1,n,dfn[x],dfn[x],val[x],y);
            val[x]=y;
        } else{
            int l=0,r=1e8,ans=1e8;
            while(l<=r){
                int mid=l+r>>1;
                if(check(mid,k,x,y)) ans=mid,l=mid+1;
                else r=mid-1;
            } printf(ans==1e8?"invalid request!\n":"%d\n",ans);
        }
    } return 0;
}

然后是\(O(n\log^2n)\)

#include<cctype>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
const int N=80005;
typedef double db;
typedef long long ll;
const int M=10000010;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define mp(A,B) std::make_pair(A,B)

int s1[N<<1],s2[N<<1];
int n,m,cnt,tot,val[N],sze[N];
int k[N],x[N],y[N],g[N<<1],len;
int ch[M][2],root[N],f[N][19];
int head[N],sum[M],dfn[N],d[N];

struct Edge{
    int to,nxt;
}edge[N<<1];

void add(int x,int y){
    edge[++cnt].to=y;
    edge[cnt].nxt=head[x];
    head[x]=cnt;
}

int getint(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch))w|=ch=='-',ch=getchar();
    while( isdigit(ch))X=X*10+ch-48,ch=getchar();
    return w?-X:X;
}

void dfs(int now){
    sze[now]=1;dfn[now]=++tot;
    for(int i=head[now];i;i=edge[i].nxt){
        int to=edge[i].to;
        if(sze[to]) continue;
        f[to][0]=now;d[to]=d[now]+1;
        for(int j=1;j<=17;j++) f[to][j]=f[f[to][j-1]][j-1];
        dfs(to);sze[now]+=sze[to];
    }
}

void pushup(int cur){
    sum[cur]=sum[ch[cur][0]]+sum[ch[cur][1]];
}

void modify(int &cur,int ql,int c,int l=1,int r=len){
    if(!cur) cur=++tot;
    if(l==r){sum[cur]+=c;return;}
    int mid=l+r>>1;
    if(ql<=mid) modify(ch[cur][0],ql,c,l,mid);
    else modify(ch[cur][1],ql,c,mid+1,r);
    pushup(cur);
}

void add(int x,int y,int z){
    while(x<=n)
        modify(root[x],y,z),x+=x&-x;
}

int lca(int x,int y){
    if(d[x]<d[y]) swap(x,y);
    for(int i=17;~i;i--)
        if(d[f[x][i]]>=d[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=17;~i;i--)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}

int query(int k,int l=1,int r=len){
    if(l==r) return l;
    int now=0,mid=l+r>>1;
    for(int i=1;i<=s1[0];i++) now+=sum[ch[s1[i]][1]];
    for(int i=1;i<=s2[0];i++) now-=sum[ch[s2[i]][1]];
    if(now>=k){
        for(int i=1;i<=s1[0];i++) s1[i]=ch[s1[i]][1];
        for(int i=1;i<=s2[0];i++) s2[i]=ch[s2[i]][1];
        return query(k,mid+1,r);
    } else{
        for(int i=1;i<=s1[0];i++) s1[i]=ch[s1[i]][0];
        for(int i=1;i<=s2[0];i++) s2[i]=ch[s2[i]][0];
        return query(k-now,l,mid);
    }
}

void ask(int k,int a,int b){
    int c=lca(a,b),dd=f[c][0];s1[0]=s2[0]=0;
    if(d[a]+d[b]-d[c]-d[dd]<k) {printf("invalid request!\n");return;}
    for(int i=dfn[a];i;i-=i&-i) s1[++s1[0]]=root[i];
    for(int i=dfn[b];i;i-=i&-i) s1[++s1[0]]=root[i];
    for(int i=dfn[c];i;i-=i&-i) s2[++s2[0]]=root[i];
    for(int i=dfn[dd];i;i-=i&-i) s2[++s2[0]]=root[i];
    printf("%d\n",g[query(k)]);
}

signed main(){
    n=getint(),m=getint();
    for(int i=1;i<=n;i++) val[i]=getint(),g[++len]=val[i];
    for(int i=1;i<n;i++){
        int x=getint(),y=getint();
        add(x,y);add(y,x);
    }
    for(int i=1;i<=m;i++){
        k[i]=getint(),x[i]=getint(),y[i]=getint();
        if(!k[i]) g[++len]=y[i];
    }
    std::sort(g+1,g+1+len);len=std::unique(g+1,g+1+len)-g-1;
    for(int i=1;i<=n;i++) val[i]=std::lower_bound(g+1,g+1+len,val[i])-g;
    for(int i=1;i<=m;i++) if(!k[i]) y[i]=std::lower_bound(g+1,g+1+len,y[i])-g;
    d[1]=1;dfs(1);tot=0;
    for(int i=1;i<=n;i++) add(dfn[i],val[i],1),add(dfn[i]+sze[i],val[i],-1);
    for(int i=1;i<=m;i++){
        if(!k[i]) add(dfn[x[i]],val[x[i]],-1),add(dfn[x[i]]+sze[x[i]],val[x[i]],1),val[x[i]]=y[i],add(dfn[x[i]],val[x[i]],1),add(dfn[x[i]]+sze[x[i]],val[x[i]],-1);
        else ask(k[i],x[i],y[i]);
    } return 0;
}

转载于:https://www.cnblogs.com/YoungNeal/p/9698700.html

### Windows 上安装 JDK、Redis、Maven 和 Node.js 的步骤 #### 安装 JDK 在 Windows 平台上安装 JDK 是构建 Java 开发环境的基础。以下是具体操作方法: 1. 访问 Oracle 或 OpenJDK 官方网站下载适合的 JDK 版本。 2. 下载完成后运行 `.exe` 文件并按照提示完成安装过程。 3. 配置系统环境变量 `JAVA_HOME`,将其指向 JDK 的安装目录[^1]。 ```bash set JAVA_HOME=C:\Program Files\Java\jdk-xx.x.x ``` 4. 将 `%JAVA_HOME%\bin` 添加到系统的 PATH 变量中以便全局调用 `java` 命令。 --- #### 安装 Redis Redis 是一种高性能键值存储数据库,在开发环境中常用于缓存服务。其安装流程如下: 1. 从官方 GitHub 页面或其他可信资源获取适用于 Windows 的 Redis 执行文件包。 2. 解压该压缩包至目标目录(如 C:\redis),无需额外编译或复杂配置即可直接使用。 3. 使用命令行启动 Redis Server 和 Client 工具来验证基本功能是否正常工作。 ```cmd cd C:\redis .\redis-server.exe redis.windows.conf ``` --- #### 安装 Apache Maven 对于基于 Java 的项目管理工具——Maven 来说,正确的部署同样重要: 1. 到官网下载最新稳定版二进制分发档 ZIP 形式; 2. 提取解压后的资料夹放置于任意固定盘符下比如 D:\tools\apache-maven-x.y.z; 3. 设置新的用户级别或者系统级别的环境变量 MAVEN_HOME 对应上述实际路径;同时更新 Path 中加入 %MAVEN_HOME%\bin%[^3]%。 另外如果希望自定义本地库地址,则编辑 settings.xml 文件中的 `<localRepository>` 节点指定新位置[^4]: ```xml <localRepository>C://ctsc//MavenRepository</localRepository> ``` --- #### 安装 Node.js (含 NPM/Yarn 支持) 最后一步就是集成前端依赖解决器 Node.js 进入我们的技术栈里头啦! 1. 登录 https://nodejs.org/ 获取 LTS Long Term Support 版本链接进行下载适配当前 OS 架构类型的 MSI Installer; 2. 同样遵循图形界面引导直至结束整个进程; 3. 测试成功与否通过打开 PowerShell 输入 node -v 查看版本号确认无误之后再继续下面几步设置个性化选项[^2]. 为了更灵活控制模块全局安装地点可以执行以下语句更改默认前缀设定: ```powershell npm config set prefix "D:\custom\node_global" ``` 至于 Yarn ,它作为另一个流行的 JavaScript 包管理解决方案也可以单独另行追加进来但这里不再赘述了因为本质上两者作用相似互相兼容良好所以任选其中之一就够用了. --- ### 总结 以上就是在一台标准 PC 设备上面针对软件工程师日常需求所描述的一套完整的跨平台开源组件集合实施方案概述文档内容摘抄改编而成的结果呈现形式之一而已实际上每种产品都有各自更加详尽深入的帮助手册可供查阅学习参考之便利于不同层次水平读者按需索取吸收理解掌握应用实践提高效率减少重复劳动成本节约时间精力创造更大价值回报社会贡献力量共同进步成长成就梦想未来无限可能等待探索发现挖掘利用转化变现共赢共享共创美好生活新时代新征程新篇章开启序幕拉开帷幕隆重登场亮相表演展示表现风采魅力特色亮点优势竞争力吸引力感染力影响力号召力凝聚力战斗力执行力行动力创造力创新力突破力进取心责任心使命感荣誉感归属感幸福感安全感获得感满足感成就感自豪感骄傲感光荣感尊严感尊重感信任感认同感支持度配合度协作精神团队意识集体观念大局观战略眼光战术布局规划方案设计思路理念原则方针政策法规制度规范准则标准衡量评价考核评估监督机制体系架构框架结构组成成分要素构成部分整体关系联系关联互动交流沟通协调平衡和谐统一融合贯通渗透影响改变塑造形成发展演变进化规律趋势方向目标愿景使命价值观文化传统习俗习惯行为模式思维定势认知偏见局限束缚解放开放包容接纳欢迎鼓励激励鼓舞启发诱导引导教导教育培养训练锻炼提升强化巩固深化细化量化质化标准化规范化程序化自动化智能化数字化信息化网络化全球化本土化区域化地方化特色化差异化同质化趋同化一致性连贯性持续性稳定性可靠性安全性隐私保护数据加密传输协议网络安全防护措施策略手段方式方法技巧窍门秘诀要领关键核心重点难点热点焦点争议话题讨论辩论对话访谈采访调查问卷统计分析研究探讨考察参观访问旅游观光休闲娱乐放松减压调节情绪心理状态身体健康状况生活质量幸福指数满意度忠诚度回头率转化率点击率浏览量曝光度知名度美誉度品牌效应市场占有率份额竞争态势对手情报收集整理归纳总结提炼升华萃取精华去粗取精去伪存真返璞归真还原真相揭示本质洞察先机抢占高地占据主动权掌控局面把握机遇迎接挑战克服困难解决问题达成共识实现双赢多赢全赢最终胜利成果辉煌灿烂美好明天光辉前景伟大事业宏伟蓝图壮丽画卷波澜壮阔气势磅礴震撼人心振奋士气凝聚力量团结一心众志成城共克时艰勇往直前披荆斩棘乘风破浪扬帆远航驶向成功的彼岸抵达理想的港湾享受甜蜜的爱情品尝美味的食物欣赏优美的音乐观看精彩的电影阅读经典的书籍增长见识开阔视野拓展胸襟陶冶情操修身养性齐家治国平天下立德树人育新人传道授业解惑也已告一段落至此圆满落幕谢谢大家聆听分享交流互鉴互利互助互惠合作共赢携手同行一路向前永不停歇直到永远阿弥陀佛南无阿弥陀佛愿一切众生皆得解脱自在逍遥快乐无忧烦恼尽消智慧光明普照大地万物复苏生机勃勃春暖花开鸟语花香柳绿桃红百花争艳千姿百态万紫千红竞相绽放绚丽多彩五彩斑斓美不胜收令人流连忘返回味无穷意犹未尽期待下次再见拜拜👋😊💕✨🌟🎉🎊🎈🎁💝💰💎💳💼🎯🏆🏅👏💪👍👌🙌🙏🤝❤️🧡💛💚💙💜🖤🤍🤎🩷🩸🔥⚡💥💫💦💨🌬🌈☀️☁️⛅🌤🌥🌧🌦⛈🌩🌨❄️☃️⛄🌊💧🌍🌐🗺📍📌🚀✈️🚂🚗🚕🚲🛺🚏🛣🛤🚉
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值