题解 CF600E 【Lomsat gelral】
没有多少人用莫队做吗?
蒟蒻水一波莫队
这是一道树上莫队好题。
时间复杂度(\(n\sqrt{n}logn\))
蒟蒻过菜,不会去掉logn的做法qaq
思路很简单:
1.dfs跑一下树上点的dfs序。
2.将树上点按dfs序进行\(\sqrt{n}\) 分块。
3.对每个点按左端点的块序号和右端点的大小排序。
inline int cmp(Node aa,Node bb)
{
return aa.ls==bb.ls?aa.r<bb.r:aa.ls<bb.ls;
}
4.开始莫队,用num[x]数组统计出现x次的颜色的序号和。转移时将原先的减去,再加上现在的。
inline void add(int x)
{
int xx=coll[x];
if(num[xx])
add(num[xx],-xx,1);
num[xx]++;
add(num[xx],xx,1);
}
inline void del(int x)
{
int xx=coll[x];
add(num[xx],-xx,1);
num[xx]--;
if(num[xx])
add(num[xx],xx,1);
}
5.将num用线段树维护最大值。
6.查找num[x]中使num[x]!=0的x最大值,并num[x]为答案。(用线段树维护)
p.s.程序理论上时间复杂度爆了,但是经过我在考场上拍的时候没有多少数据可以卡掉,并且可以卡掉这个程序的数据第二次试的时候就不会爆,所以这个程序只要评测机高兴,就不会挂。
上代码(预警,代码中含有大量无用数组)
码长:3000B
当当当当
#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
inline ll read()
{
ll f=0,x=1;char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')x=-1;ch=getchar();
}
while(ch>='0'&&ch<='9')f=(f<<1)+(f<<3)+ch-'0',ch=getchar();
return f*x;
}
ll n,col[100009],siz,cnt=0,head[100009],dfn[100009],
l[100009],r[100009],num[100009],ans=0,maxx=0,anss[100009],
coll[100009];
struct edge
{
ll to,nxt;
}e[200009];
struct Node
{
ll l,r,id,bh,col,ls,rs;
}a[100009];
struct segtree
{
ll l,r,w;
}tree[400009];
inline void adde(int a,int b)
{
cnt++;
e[cnt].nxt=head[a];
e[cnt].to=b;
head[a]=cnt;
}
inline void dfs(int x,int fa)
{
dfn[x]=++cnt;
l[cnt]=x;coll[cnt]=col[x];
a[cnt].id=x;a[cnt].l=cnt;a[cnt].col=col[x];
for(int i=head[x];~i;i=e[i].nxt){
int v=e[i].to;
if(v==fa)continue;
dfs(v,x);
}
r[x]=cnt;
a[dfn[x]].r=cnt;
}
inline int cmp(Node aa,Node bb)
{
return aa.ls==bb.ls?aa.r<bb.r:aa.ls<bb.ls;
}
inline void build(int l,int r,int p)
{
tree[p].l=l;tree[p].r=r;
if(l==r)
return ;
int mid=(l+r)>>1;
build(l,mid,p*2);build(mid+1,r,p*2+1);
}
inline void add(int x,int xx,int p)
{
if(tree[p].l==tree[p].r)
{
tree[p].w+=xx;
//printf("%d %d %d\n",tree[p].l,tree[p].r,tree[p].w);
return ;
}
int mid=(tree[p].l+tree[p].r)>>1;
if(x<=mid)add(x,xx,p*2);
else add(x,xx,p*2+1);
tree[p].w=tree[p*2].w+tree[p*2+1].w;
//printf("%d %d %d %d\n",tree[p].l,tree[p].r,tree[p].w,xx);
}
inline void add(int x)
{
int xx=coll[x];
//ans[num[xx]]-=x;
if(num[xx])
add(num[xx],-xx,1);
num[xx]++;
add(num[xx],xx,1);
//printf("!!!%d %d %d\n",x,xx,a[x].id);
//ans[num[xx]]+=x
//if(num[x]==maxx)ans+=x;
}
inline void del(int x)
{
int xx=coll[x];
add(num[xx],-xx,1);
num[xx]--;
//printf("!!!%d %d %d\n",x,xx,a[x].id);
if(num[xx])
add(num[xx],xx,1);
}
inline void find(int l,int r,int p)
{
if(ans)return ;
if(l<=tree[p].l&&r>=tree[p].r){
int mid=(tree[p].l+tree[p].r)>>1;
if(tree[p].l==tree[p].r){
ans=max(ans,tree[p].w);return ;
}
if(tree[p*2+1].w)find(l,r,p*2+1);
else if(tree[p*2].w)find(l,r,p*2);
return ;
}
int mid=(tree[p].l+tree[p].r)>>1;
if(r>mid)find(l,r,p*2+1);
if(l<=mid)find(l,r,p*2);
}
int main()
{
n=read();siz=sqrt(n);
build(1,n,1);
memset(head,-1,sizeof(head));
//printf("%d\n",n);
for(int i=1;i<=n;i++){
col[i]=read();
}
for(int i=1;i<=n-1;i++){
int a=read(),b=read();
adde(a,b);adde(b,a);
}
cnt=0;
dfs(1,1);
for(int i=1;i<=n;i++)
{
a[i].ls=(a[i].l+siz-1)/siz;
}
sort(a+1,a+n+1,cmp);
int l=1,r=0;
for(int i=1;i<=n;i++)
{
ans=0;
while(r<a[i].r)add(++r);
while(r>a[i].r)del(r--);
while(l<a[i].l)del(l++);
while(l>a[i].l)add(--l);
find(1,n,1);
anss[a[i].id]=ans;
//printf("ans %d %d %d %d\n",a[i].l,a[i].r,a[i].id,ans);
}
for(int i=1;i<=n;i++)printf("%lld ",anss[i]);
return 0;
}
题解 CF600E 【Lomsat gelral】的更多相关文章
- CF600E Lomsat gelral 和 CF741D Dokhtar-kosh paths
Lomsat gelral 一棵以\(1\)为根的树有\(n\)个结点,每个结点都有一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号(若有数量一样的,则求编号和). \(n \le 10^ ...
- 【学习笔记/题解】树上启发式合并/CF600E Lomsat gelral
题目戳我 \(\text{Solution:}\) 树上启发式合并,是对普通暴力的一种优化. 考虑本题,最暴力的做法显然是暴力统计每一次的子树,为了避免其他子树影响,每次统计完子树都需要清空其信息. ...
- CF600E Lomsat gelral 【线段树合并】
题目链接 CF600E 题解 容易想到就是线段树合并,维护每个权值区间出现的最大值以及最大值位置之和即可 对于每个节点合并一下两个子节点的信息 要注意叶子节点信息的合并和非叶节点信息的合并是不一样的 ...
- CF600E Lomsat gelral (启发式合并)
You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour. Let's cal ...
- CF600E Lomsat gelral (dfs序+莫队)
题面 题解 看到网上写了很多DSU和线段树合并的题解,笔者第一次做也是用的线段树合并,但在原题赛的时候却怕线段树合并调不出来,于是就用了更好想更好调的莫队. 这里笔者就说说莫队怎么做吧. 我们可以通过 ...
- CF600E Lomsat gelral(dsu on tree)
dsu on tree跟冰茶祭有什么关系啊喂 dsu on tree的模板题 思想与解题过程 类似树链剖分的思路 先统计轻儿子的贡献,再统计重儿子的贡献,得出当前节点的答案后再减去轻儿子对答案的贡献 ...
- CF600E:Lomsat gelral(线段树合并)
Description 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. Input 第一行一个$n$.第二行$n$个数字是$c[i]$.后面$n-1$ ...
- [CF600E]Lomsat gelral
题意翻译 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. 线段树合并板子题,没啥难度,注意开long long 不过这题$dsu$ $on$ $tre ...
- dsu on tree(CF600E Lomsat gelral)
题意 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. dsu on tree 用来解决子树问题 好像不能带修改?? 暴力做这个题,就是每次扫一遍子树统 ...
- cf600E. Lomsat gelral(dsu on tree)
题意 题目链接 给出一个树,求出每个节点的子树中出现次数最多的颜色的编号和 Sol dsu on tree的裸题. 一会儿好好总结总结qwq #include<bits/stdc++.h> ...
随机推荐
- 21 (OC) 数据持久化
概论 所谓的持久化,就是将数据保存到硬盘中,使得在应用程序或机器重启后可以继续访问之前保存的数据.在iOS开发中,有很多数据持久化的方案,接下来我将尝试着介绍一下5种方案: plist文件(属性列表) ...
- [LeetCode] 由 “中缀表达式 --> 后缀表达式" 所想
如何利用栈解决问题. Ref: 如何在程序中将中缀表达式转换为后缀表达式? 本文的引申:如何手写语法分析器 实现调度场算法 “9+(3-1)*3+10/2” --> “9 3 1-3*+ 10 ...
- java中String常见问题
java中String常见问题 1.字符串比较==和equals ==:比较的是对象,判断两个引用的是否为同一内存地址(物理对象) equals:比较的是值 2.通过空白字符拆封字符串 str.spi ...
- 夯实Java基础系列5:Java文件和Java包结构
目录 Java中的包概念 包的作用 package 的目录结构 设置 CLASSPATH 系统变量 常用jar包 java软件包的类型 dt.jar rt.jar *.java文件的奥秘 *.Java ...
- wait()与notify()
一,前言 简单画了一下线程的流程图,只是一个大概.如图所示,线程有多种状态,那么不同状态之间是如何切换的,下面主要总结关于wait()和notify()的使用. 二,wait() wait ...
- js中的计时器事件`setTimeout()` 和 `setInterval()`
js中的计时器事件 在js中,通常会有一些事件,我们需要让它 间隔一段时间之后再发生,或者 每隔一段时间 发生一次,那就需要用到我们js中的计时事件 计时事件主要有两种: setTimeout() - ...
- C语言I—2019秋作业02
1.[新增内容] 这个作业属于那个课程 C语言程序设计 这个作业要求在哪里 <C语言I-2019秋作业02> 我在这个课程的目标是 这个作业在那个具体方面帮助我实现目标 <实现一些基 ...
- IntelliJ IDEA 如何在同一个窗口创建多个项目--超详细教程
一.IntelliJ IDEA与Eclipse的区别 二.在同一个窗口创建多个项目 1.打开IntelliJ IDEA,点击Create New Project 2.Java Enterprise-- ...
- grep、正则表达式
1.grep :文本搜索工具 -i:忽略大小写--color:匹配到的内容高亮显示-v:显示没有被模式匹配到的行-o:只显示被模式匹配到的字符串-n:显示匹配到行的行号-E:使用扩展正则表达式-A:后 ...
- 文件操作——RandomAccessFile
文件操作——RandomAccessFile 构建RandomAccessFileJava提供了一个可以对文件随机访问的操作,访问包括读和写操作.该类名为RandomAccessFile.该类的读 ...