轻重链剖分+启发式合并专题

news2025/1/15 20:42:35

Codeforces-741D(Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths)

一棵根为1 的树,每条边上有一个字符(a-v共22种)。 一条简单路径被称为Dokhtar-kosh当且仅当路径上的字符经过重新排序后可以变成一个回文串。 求每个子树中最长的Dokhtar-kosh路径的长度。给你n个点构成的一棵树,树里面的每一条边有一个权值,求出每个子树里面能通过重排构成回文串的最大路径长度.

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,M=2*N;
int h[N],e[M],ne[M],w[M],idx;
int n,id[N],L[N],R[N],o,son[N],sz[N],dep[N],dfn[N];
int d[N],f[1<<23],ans[N],flag;
void add(int a,int b,int c){
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int fa=0){
    dep[u]=dep[fa]+1;
    dfn[u]=++o,id[o]=u;
    sz[u]=1;
    L[u]=o;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==fa)continue;
        d[j]=d[u]^w[i];//d[j]表示从根节点到j的结点状态
        
        dfs1(j,u);
        sz[u]+=sz[j];
        if(sz[son[u]]<sz[j])son[u]=j;
    }
    R[u]=o;
}
void upd(int u){
    if(f[d[u]])ans[u]=max(ans[u],f[d[u]]-dep[u]);
    for(int i=0;i<22;i++){
        int x=d[u]^(1<<i);
        if(f[x])ans[u]=max(ans[u],f[x]-dep[u]);
    }
}
void upd2(int j,int u){
    if(f[d[j]])ans[u]=max(ans[u],f[d[j]]+(dep[j]-dep[u])-dep[u]);
    for(int i=0;i<22;i++){
        int x=d[j]^(1<<i);
        if(f[x])ans[u]=max(ans[u],f[x]+(dep[j]-dep[u])-dep[u]);
    }
}
void cal(int u,int fa){
    upd(u);//先更新贡献
    f[d[u]]=max(f[d[u]],dep[u]);//把我自己插进去
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==son[u]||j==fa)continue;
        for(int x=L[j];x<=R[j];x++)upd2(id[x],u);//计算子树所有节点和我构成的贡献
        for(int x=L[j];x<=R[j];x++)f[d[id[x]]]=max(f[d[id[x]]],dep[id[x]]);//插入这颗子树的贡献
    }
}
void dfs(int u,int fa=0,int keep=0){
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==fa||j==son[u])continue;//先枚举轻儿子,不保留
        dfs(j,u,0);
        ans[u]=max(ans[u],ans[j]);
    }
    if(son[u]){//再计算重儿子,保留答案
        int j=son[u];
        dfs(j,u,1);
        ans[u]=max(ans[u],ans[j]);
        flag=j;
    }
    cal(u,fa);//计算跟u节点相关的答案
    flag=0;
    if(!keep)for(int i=L[u];i<=R[u];i++)f[d[id[i]]]=0;
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    memset(h,-1,sizeof h);char c;
    for(int i=2,j;i<=n;i++)cin>>j>>c,add(j,i,1<<(c-'a')),add(i,j,1<<(c-'a'));
    dfs1(1);
    dfs(1);
    for(int i=1;i<=n;i++)cout<<ans[i]<<" ";
}

阔力梯的树

在这里插入图片描述

用启发式合并写

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
int n,sz[N];
long long f[N];
vector<int>g[N],son[N];
set<int>S[N];
void dfs(int u){
    sz[u]=1;
    S[u].insert(u);
    for(auto j:g[u]){
        dfs(j);
        if(sz[u]<sz[j])swap(sz[u],sz[j]),swap(S[u],S[j]),f[u]=f[j];
        //这里swap有一个坑点,f[j]是你最后要用的,已经记录好了的不要乱动,u用了j的set直接从f[j]就好了
        for(auto x:S[j]){
            auto it=S[u].lower_bound(x);
            if(it==S[u].begin())f[u]+=(x-*it)*(x-*it);
            else if(it==S[u].end())it--,f[u]+=(x-*it)*(x-*it);
            else{
                int r=*it;
                it--;
                int l=*it;
                f[u]-=(r-l)*(r-l);
                f[u]+=(x-l)*(x-l)+(x-r)*(x-r);
            }
            S[u].insert(x);
        }
        sz[u]+=sz[j];
    }
}

signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=2;i<=n;i++){
        int fa;
        cin>>fa;
        g[fa].push_back(i);
    }
    dfs(1);
    for(int i=1;i<=n;i++)cout<<f[i]<<'\n';
}

用树链剖分写

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
int n,h[N],ne[N],e[N],idx;
int sz[N],id[N],L[N],R[N],o,son[N],ans[N];
set<int>S;
int f;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dsu(int u){
    sz[u]=1;
    L[u]=++o,id[o]=u;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        dsu(j);
        if(sz[j]>sz[son[u]])son[u]=j;
        sz[u]+=sz[j];
    }
    R[u]=o;
}
void ins(int x){
    if(S.empty()){
        S.insert(x);
        return;
    }
    auto it=S.lower_bound(x);
    if(it==S.begin())f+=(x-*it)*(x-*it);
    else if(it==S.end())it--,f+=(x-*it)*(x-*it);
    else{
        int r=*it;
        it--;
        int l=*it;
        f-=(r-l)*(r-l);
        f+=(r-x)*(r-x)+(x-l)*(x-l);
    }
    S.insert(x);
}
void dfs(int u,int keep=0){
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==son[u])continue;
        dfs(j,0);
    }
    if(son[u])dfs(son[u],1);
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==son[u])continue;
        for(int k=L[j];k<=R[j];k++)ins(id[k]);
    }
    ins(u);
    ans[u]=f;
    if(!keep)f=0,S.clear();
}

signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=2;i<=n;i++){
        int fa;
        cin>>fa;
        add(fa,i);
    }
    dsu(1);
    dfs(1);
    for(int i=1;i<=n;i++)cout<<ans[i]<<'\n';
}

F. Strange Memory

在这里插入图片描述

#include<bits/stdc++.h>
// #define int long long
using namespace std;
const int N=2e5+10,M=1e6+5e5;
int n,h[N],e[N],ne[N],idx,a[N];
int L[N],R[N],id[N],o,sz[N],son[N];
int f[2][20][M];
long long ans;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dsu(int u,int fa=0){
    sz[u]=1;
    L[u]=++o;id[o]=u;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==fa)continue;
        dsu(j,u);
        if(sz[j]>sz[son[u]])son[u]=j;
        sz[u]+=sz[j];
    }
    R[u]=o;
}
void ins(int u,int k=1){
    for(int i=0;i<20;i++){
        int x=u>>i&1;
        f[x][i][a[u]]+=k;
    }
}
void cal(int u,int need){
    for(int i=0;i<20;i++){
        int x=u>>i&1;
        ans+=(1ll<<i)*(f[x^1][i][a[u]^need]);
    }
}
void dfs(int u,int fa=0,int keep=0){
    
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==fa||j==son[u])continue;
        dfs(j,u,0);
    }
    if(son[u])dfs(son[u],u,1);
    ins(u);//先去递归,再插入我自己,不然会wa
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==fa||j==son[u])continue;
        for(int x=L[j];x<=R[j];x++)cal(id[x],a[u]);
        for(int x=L[j];x<=R[j];x++)ins(id[x]);
    }
    if(!keep)for(int i=L[u];i<=R[u];i++)ins(id[i],-1);
}

signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    memset(h,-1,sizeof h);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    dsu(1);
    dfs(1);
    cout<<ans;
}

E. Blood Cousins Return

树上gcd(x,y)==x^y的个数,操作1,插入新节点a[x]=v,操作2,合并x和y子树,操作3,把a[x]->v

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int n,m,p[N],sz[N],a[N];
ll ans;
vector<int>g[N];//g[i]表示i可能的答案,枚举i的约数存入进去
unordered_map<int,int>mp[N];
int find(int x){
    if(p[x]==x)return x;
    return p[x]=find(p[x]);
}
// a^b==gcd(a,b)有多少对
//a^b>=|a-b|>=gcd(a,b)


void merge(int x,int y){
    x=find(x),y=find(y);
    if(x==y)return;
    if(sz[x]<sz[y])swap(mp[x],mp[y]),swap(sz[x],sz[y]);
    for(auto [k,v]:mp[y]){
        for(auto t:g[k])if(mp[x].count(t))ans+=(ll)mp[x][t]*v;
    }
    for(auto [k,v]:mp[y])mp[x][k]+=v;
    mp[y].clear();
    p[y]=x;
    sz[x]+=sz[y];
}
void so(int x){
    for(int d=1;d*d<=x;d++){
        if(x%d)continue;
        int i=d,j=x/i,y;
        y=x-i;if((x^y)==__gcd(x,y)&&y>0)g[x].push_back(y);
        y=x+i;if((x^y)==__gcd(x,y)&&y<=2e5)g[x].push_back(y);
        if(i==j)continue;
        y=x-j;if((x^y)==__gcd(x,y)&&y>0)g[x].push_back(y);
        y=x+j;if((x^y)==__gcd(x,y)&&y<=2e5)g[x].push_back(y);
    }
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // for(int i=1;i<=2e5;i++)so(i);
    for (int i = 1; i <= 200000; i++) {
		for (int j = i + i; j <= 200000; j += i) {
			if (gcd(j, i^j) == i)g[j].push_back(i^j);
		}
	}
    cin>>n>>m;
    for(int i=1;i<=n+m;i++)p[i]=i,sz[i]=1;
    for(int i=1;i<=n;i++)cin>>a[i],mp[i][a[i]]++;
    while(m--){
        int op,x;
        cin>>op;
        if(op==1){int v;cin>>x>>v;a[x]=v;mp[x][v]=1;}
        if(op==2){int y;cin>>x>>y;merge(x,y);}
        if(op==3){
            int v;cin>>x>>v;
            int u=find(x);
            for(auto t:g[a[x]])if(mp[u].count(t))ans-=mp[u][t];
            mp[u][a[x]]--;
            a[x]=v;
            for(auto t:g[a[x]])if(mp[u].count(t))ans+=mp[u][t];
            mp[u][a[x]]++;
        }
        cout<<ans<<'\n';
    }
}
#include<bits/stdc++.h>
// #define int long long
using namespace std;
const int N=3e5+10;
int n,m,a[N],p[N];
long long ans;
vector<int>g[N];
int find(int x){
    if(p[x]==x)return x;
    return p[x]=find(p[x]);
}
void init(){
    for(int i=1;i<=2e5;i++){
        for(int j=i+i;j<=2e5;j+=i){
            if(__gcd(j,i^j)==i)g[j].push_back(i^j);
        }
    }
}
unordered_map<int,int>mp[N];
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    init();
    cin>>n>>m;
    for(int i=1;i<N;i++)p[i]=i;
    for(int i=1;i<=n;i++)cin>>a[i],mp[i][a[i]]=1;
    while(m--){
        int op,x,v;
        cin>>op>>x>>v;
        if(op==1)a[x]=v,p[x]=x,mp[x][v]=1;
        if(op==2){
            x=find(x),v=find(v);
            if(x!=v){
                if(mp[x].size()<mp[v].size())swap(mp[x],mp[v]);
                for(auto [a,c]:mp[v]){
                    for(auto need:g[a])if(mp[x].count(need))ans+=(long long)c*mp[x][need];
                }
                for(auto [a,c]:mp[v])mp[x][a]+=c;
                // mp[v].clear();
                p[v]=x;
            }
        }
        if(op==3){
            int fa=find(x);
            int c=1;
            for(auto need:g[a[x]])if(mp[fa].count(need))ans-=c*mp[fa][need];
            mp[fa][a[x]]--;
            a[x]=v;
            for(auto need:g[a[x]])if(mp[fa].count(need))ans+=c*mp[fa][need];
            mp[fa][a[x]]++;
        }
        cout<<ans<<'\n';
    }
    
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1108225.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第三章 内存管理 九、基本分段存储管理方式

目录 一、概括 二、什么是分段 三、段表 四、地址转换 五、分段和分页的对比 六、总结 一、概括 基本分段存储管理方式是一种操作系统的内存管理方式&#xff0c;采用这种方式&#xff0c;将进程所需的内存分成若干个段&#xff0c;每个段都可以单独进行管理和保护。 具…

分享一下怎么开发一个陪诊小程序

开发一个陪诊小程序需要综合考虑许多方面&#xff0c;包括但不限于市场需求、用户体验、技术实现和运营策略。以下是一篇以开发陪诊小程序为主题的文章。 一、背景介绍 随着社会的发展和人口老龄化的加剧&#xff0c;越来越多的老年人、病患和孕妇需要就医&#xff0c;而由于各…

攻防世界web篇-unserialize3

得出php代码残篇 将代码补全后再在线php运行工具中进行运行 在浏览器输入后得到下面的界面 这里需要将O:4:“xctf”:1:{s:4:“flag”;s:3:“111”;} 改为 O:4:“xctf”:2:{s:4:“flag”;s:3:“111”;}

【Leetcode】212.单词搜索II(Hard)

一、题目 1、题目描述 给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words, 返回所有二维网格上的单词 。 单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中…

【java】Java项目从开发到部署生产完整流程梳理

文章目录 前言一、开发环境二、项目搭建2.1 Maven创建项目2.1.1 创建maven项目2.1.2 引入依赖2.1.3 maven常用命令 三、SpringBoot基础配置四、项目打包4.1 打包jar4.2 打包war4.2.1 修改项目打包为war包4.2.2 排除内嵌的tomcat&#xff0c;引入外部tomcat4.2.3 添加servlet-ap…

Unity可视化Shader工具ASE介绍——8、UI类型的特效Shader编写

阿赵的Unity可视化Shader工具ASE介绍目录 Unity的UGUI图片特效角色闪卡效果 大家好&#xff0c;我是阿赵。   继续介绍Unity可视化Shader编辑插件ASE的使用。这次讲一下UI类特效Shader的写法。 一、例子说明 这次编写一个Shader&#xff0c;给一张UGUI里面的图片增加一个闪卡…

攻防世界web篇-Training-WWW-Robots

直接点击给出的地址&#xff0c;然后会转到另一个网页界面&#xff0c;在这个界面&#xff0c;已经给出了提示&#xff0c;robots.txt 在浏览器中&#xff0c;直接在地址的后面加上robots.txt&#xff0c;会进到下面这个界面 因为对php语言一窍不通&#xff0c;所以这里纯粹就…

Swagger有哪些非常重要的注释?

Swagger是一种用于描述和定义RESTful API的强大工具&#xff0c;它提供了一种规范来编写API文档&#xff0c;生成客户端SDK以及进行自动化测试。其中的注释&#xff08;Annotations&#xff09;在Swagger规范中扮演着关键的角色&#xff0c;用于为API端点、操作、模型等添加元数…

在UniApp中使用uni.makePhoneCall方法调起电话拨打功能

目录 1.在manifest.json文件中添加权限 2. 组件中如何定义 3.如何授权 4.相关知识点总结 1.在manifest.json文件中添加权限 {"permissions": {"makePhoneCall": {"desc": "用于拨打电话"}} }2. 组件中如何定义 <template>…

Spring Security的认证和授权(1)

1、Spring Security 简介 Java企业级开发生态丰富&#xff0c;无论你想做哪方面的功能&#xff0c;都有众多的框架和工具可供选择, 以至于SUN公司在早些年不得不制定了很多规范&#xff0c;这些规范在今天依然影响着我们的开发&#xff0c; 安全领域也是如此&#xff0c;然而&…

TOGAF架构开发方法—初步阶段

本章描述了满足新企业体系结构业务指令所需的准备和启动活动,包括组织特定体系结构框架的定义和原则的定义。 一、目标 初步阶段的目标是: 确定组织所需的体系结构功能: 审查进行企业架构的组织背景确定受体系结构功能影响的企业组织的元素并确定其范围确定与架构功能相交的…

php 遍历PHP数组的7种方式

在PHP中&#xff0c;遍历数组有多种方式可以选择。以下是最常用的几种方式&#xff1a; 使用foreach循环 $array array("apple", "banana", "orange"); foreach($array as $value){echo $value . "<br>"; } 输出结果&#xff…

工程监测仪器振弦传感器信号转换器在桥梁安全监测中的重要性

工程监测仪器振弦传感器信号转换器在桥梁安全监测中的重要性 桥梁是人类社会建设过程中最重要的交通基础设施之一&#xff0c;对于保障人民出行、促进经济发展具有极其重要的作用。由于桥梁结构在长期使用过程中受到环境因素和负荷的影响&#xff0c;会逐渐发生变形和损伤&…

QT学习笔记-QT程序执行Linux Shell命令实现动态添加路由

QT学习笔记-QT程序执行Linux Shell命令实现动态添加路由 背景关键代码程序界面 背景 在使用QT进行Linux下应用程序开发时&#xff0c;在特定业务需求下&#xff0c;需要在程序中执行Linux的Shell命令。QT中执行Linux命令可以通过QProcess类和system来实现&#xff0c;如果需要…

使用 Service 把前端连接到后端

使用 Service 把前端连接到后端 如何创建前端&#xff08;Frontend&#xff09;微服务和后端&#xff08;Backend&#xff09;微服务。后端微服务是一个 hello 欢迎程序。 前端通过 nginx 和一个 Kubernetes 服务暴露后端所提供的服务。 使用部署对象&#xff08;Deployment ob…

Android Gradle权威指南读书笔记

第一章 Gradle入门 生成Gradle Wrapper 命令&#xff1a;gradle wrapper --gradle-version 版本号自定义Gradle Wrapper task wrapper(type : Wrapper) { gradleVersion 2.4 archiveBase GRADLE USER HOME archivePath wrapper/dists distributionBase GRADLE USER HOME …

基于PHP的宠物爱好者交流平台管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

windows下8.0版本mysql创建用户并授权

简单记录下&#xff0c;可能有些杂乱 root用户登录mysql 创建用户 create user 要创建的用户名允许连接的ip identified by 用户名对应的密码; flush privileges; //刷新权限举个例子&#xff1a; create user test1localhost identified by test1; flush privileges; …

docker 基本用法-操作镜像

1.下载镜像 docker search centos #默认从 Docker Hub 中搜索镜像 访问 dockerhub&#xff1a;https://registry.hub.docker.com docker pull centos 拉取镜像 如果不能拉取 方法 1.需要配置配置镜像加速器 tee /etc/docker/daemon.json << EOF {"registry-mirro…

卡尔曼滤波器公式

1、卡尔曼滤波公式如下 &#xff08;1&#xff09;预测方程&#xff1a; 预测状态向量转换矩阵*上一时刻更新的状态向量 控制矩阵*当前的系统输入 /----------------------P推导 begin-----------------------------/ 预测系统状态的协方差矩阵 E[(状态向量-预测状态向量&am…