当前位置: 首页 > news >正文

[ZJOI2019]语言

[ZJOI2019]语言 

法一: O(nlog^3)树剖+矩形面积并

法二:O(nlog^2)

一个点能到达的点是所有经过它的链的链并的大小

给出m个链求链并:

类似虚树

dfn序排序,ans+=dep[mem[i]]-dep[lca(mem[i],mem[i-1])]

每个边一定会统计到。

 

维护?

每个链树剖拆成logn份,线段树分治+线段树

下标都是dfn序

dfn相邻的贡献答案

 

法三:O(nlogn)

不再从dfn序列孤立地考虑树链

从树上直接考虑

经过一个点x的链一定一端在x的子树,启发我们线段树合并!

下标还是dfn序

树上差分打标记,8个标记。

lca可以O(1)求

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout<<endl
#define pii pair<int,int>
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}

namespace Miracle{
const int N=1e5+5;
int n,m;
struct node{
    int nxt,to;
}e[2*N];
int hd[N],cnt;
void add(int x,int y){
    e[++cnt].nxt=hd[x];
    e[cnt].to=y;
    hd[x]=cnt;
}

int dfn[N],df,fdfn[N];
int st[N],num;
int dep[N];
int mem[2*N];
int fa[N];
void dfs(int x,int d){
    dep[x]=d;dfn[x]=++df;
    fdfn[df]=x;
    st[x]=++num;mem[num]=x;
    for(reg i=hd[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==fa[x]) continue;
        fa[y]=x;
        dfs(y,d+1);
        mem[++num]=x;
    }
}
int anc[2*N][20];
int lg[2*N];
int lca(int x,int y){
    if(!x||!y) return 0;
    if(st[x]>st[y]) swap(x,y);
    x=st[x],y=st[y];
    int len=lg[y-x+1];
    int p1=anc[x][len],p2=anc[y-(1<<len)+1][len];
    return dep[p1]<dep[p2]?p1:p2;
}
int con(int x,int y){
    if(!x||!y) return 0;
    return dep[fdfn[y]]-dep[lca(fdfn[x],fdfn[y])];
}
struct tr{
    int ls,rs;
    int le,ri;
    int tag;
    int ans;
}t[N*160];
#define mid ((l+r)>>1)
int tot;
void pushup(int x){
    t[x].ans=t[t[x].ls].ans+t[t[x].rs].ans+con(t[t[x].ls].ri,t[t[x].rs].le);
    t[x].ri=t[t[x].rs].ri?t[t[x].rs].ri:t[t[x].ls].ri;
    t[x].le=t[t[x].ls].le?t[t[x].ls].le:t[t[x].rs].le;
}
int rt[N];
void upda(int &x,int l,int r,int p,int c){
    if(!x) x=++tot;
    if(l==r){
        t[x].tag+=c;
        if(t[x].tag>0) t[x].le=t[x].ri=l;
        else t[x].le=t[x].ri=0;
        return;
    }
    if(p<=mid) upda(t[x].ls,l,mid,p,c);
    else upda(t[x].rs,mid+1,r,p,c);
    pushup(x);
}
int merge(int x,int y,int l,int r){
    if(!x||!y) return x+y;
    if(l==r){
        t[x].tag+=t[y].tag;
        if(t[x].tag>0) t[x].le=t[x].ri=l;
        else t[x].le=t[x].ri=0;
        return x;
    }
    t[x].ls=merge(t[x].ls,t[y].ls,l,mid);
    t[x].rs=merge(t[x].rs,t[y].rs,mid+1,r);
    pushup(x);
    return x;
}
ll ans;
void sol(int x){
    for(reg i=hd[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==fa[x]) continue;
        sol(y);
        rt[x]=merge(rt[x],rt[y],1,n);
    }
    int now=t[rt[x]].ans+dep[fdfn[t[rt[x]].le]]-dep[fa[lca(fdfn[t[rt[x]].le],fdfn[t[rt[x]].ri])]];
    // cout<<" sol "<<x<<" now "<<now<<" ans "<<t[rt[x]].ans<<" "<<endl;
    if(now) ans+=now-1;
}
int main(){
    rd(n);rd(m);
    int x,y;
    for(reg i=1;i<n;++i){
        rd(x);rd(y);
        add(x,y);add(y,x);
    }
    dfs(1,1);
    for(reg i=1;i<=num;++i) {
        anc[i][0]=mem[i];
        lg[i]=(i>>(lg[i-1]+1)?lg[i-1]+1:lg[i-1]);
    }
    for(reg j=1;j<=17;++j){
        for(reg i=1;i+(1<<j)-1<=num;++i){
            anc[i][j]=dep[anc[i][j-1]]<dep[anc[i+(1<<(j-1))][j-1]]?anc[i][j-1]:anc[i+(1<<(j-1))][j-1];
        }
    } 
    for(reg i=1;i<=m;++i){
        rd(x);rd(y);
        int z=lca(x,y);
        // cout<<" zz "<<z<<endl;
        upda(rt[x],1,n,dfn[x],1);
        upda(rt[x],1,n,dfn[y],1);
        upda(rt[y],1,n,dfn[x],1);
        upda(rt[y],1,n,dfn[y],1);
        upda(rt[z],1,n,dfn[x],-1);
        upda(rt[z],1,n,dfn[y],-1);
        if(fa[z]){
            upda(rt[fa[z]],1,n,dfn[x],-1);
            upda(rt[fa[z]],1,n,dfn[y],-1);
        }
    }
    sol(1);
    // cout<<" 00 "<<rt[0]<<" "<<t[0].ans<<" "<<t[0].ls<<" "<<t[0].rs<<" "<<t[0].le<<" "<<t[0].ri<<" "<<t[0].tag<<endl;
    ans/=2;
    ot(ans);
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
*/

 

转载于:https://www.cnblogs.com/Miracevin/p/10805577.html

相关文章:

  • 迄今为止把同步/异步/阻塞/非阻塞/BIO/NIO/AIO讲的这么清楚的好文章(快快珍藏)...
  • LeetCode--047--全排列 II(java)
  • Javascript 模块化指北
  • Hadoop高可用原理及环境搭建
  • BBS项目
  • 【轻松一刻】Java制作字符动画
  • SpringBoot整合Redis使用Restful风格实现CRUD功能
  • 5、集合--Connection和Iterator接口
  • python中常用模块
  • robot framework环境搭建
  • 个人简历
  • python3 案例分享--五角星
  • 毕业倒计时开始了,你的论文答辩PPT准备好了吗?
  • vue 引入公共组件之 require.context
  • 69前端技术
  • [Vue CLI 3] 配置解析之 css.extract
  • 「译」Node.js Streams 基础
  • 【RocksDB】TransactionDB源码分析
  • ➹使用webpack配置多页面应用(MPA)
  • 3.7、@ResponseBody 和 @RestController
  • Angular数据绑定机制
  • CentOS从零开始部署Nodejs项目
  • js对象的深浅拷贝
  • Koa2 之文件上传下载
  • rabbitmq延迟消息示例
  • Redis的resp协议
  • sublime配置文件
  • vue-cli3搭建项目
  • 阿里研究院入选中国企业智库系统影响力榜
  • 从伪并行的 Python 多线程说起
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 回顾 Swift 多平台移植进度 #2
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • Hibernate主键生成策略及选择
  • ​什么是bug?bug的源头在哪里?
  • #etcd#安装时出错
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • ()、[]、{}、(())、[[]]命令替换
  • (06)金属布线——为半导体注入生命的连接
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • ... 是什么 ?... 有什么用处?
  • .NET 8.0 中有哪些新的变化?
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .NET Core 项目指定SDK版本
  • .Net FrameWork总结
  • .NET Micro Framework初体验
  • .net MVC中使用angularJs刷新页面数据列表
  • .NET 表达式计算:Expression Evaluator
  • .net中生成excel后调整宽度