5457: 城市

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 18  Solved: 12
[Submit][Status][Discuss]

Description

有n座城市,m个民族。这些城市之间由n-1条道路连接形成了以城市1为根的有根树。每个城市都是某一民族的聚居
地,Master知道第i个城市的民族是A_i,人数是B_i。为了维护稳定,Master需要知道某个区域内人数最多的民族
。他向你提出n个询问,其中第i个询问是:求以i为根的子树内,人数最多的民族有是哪个,这个民族有多少人。
如果子树内人数最多的民族有多个,输出其中编号最小的民族。

Input

共有2*n行。
第一行有两个整数n, m。
接下来n-1行,每行有两个整数u, v,表示一条连接u和v的道路。
接下来n行,第i行有两个整数A_i, B_i。
n<=400000,m<=n,1<=A_i<=m,0<=B_i<=1000。

Output

共有n行。
第i行两个整数x, y,分别表示以i为根的子树中人数最多的民族和它的人数。

Sample Input

8 6
1 2
1 3
2 4
4 5
3 6
5 7
1 8
2 8
2 5
1 1
3 1
6 7
5 6
1 10
4 6

Sample Output

2 13
1 10
5 6
1 10
1 10
5 6
1 10
4 6

思路:每个节点保存一个线段树,表示子树的民族及其数量,维护区间最大值。

然后DFS,线段树合并即可。  7500ms。再8个AC里,我的三个AC代码分别排最后三名。 亟待优化啊!

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=;
void read(int &x){
x=; char c=getchar();
while(c>''||c<'') c=getchar();
while(c>=''&&c<='') x=x*+c-'',c=getchar();
}
struct in{
int l,r,pos,mx;
in(){l=r=mx=pos=;}
}s[maxn*];
int Laxt[maxn],Next[maxn],To[maxn],cnt,M;
int A[maxn],B[maxn],rt[maxn],tot,ans[maxn][];
void add(int u,int v){
Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v;
}
void pushup(int Now){
if(s[Now].l&&!s[Now].r){
s[Now].mx=s[s[Now].l].mx; s[Now].pos=s[s[Now].l].pos;
}
else if(s[Now].l&&s[Now].r&&s[s[Now].l].mx>=s[s[Now].r].mx){
s[Now].mx=s[s[Now].l].mx; s[Now].pos=s[s[Now].l].pos;
}
else s[Now].mx=s[s[Now].r].mx,s[Now].pos=s[s[Now].r].pos;
}
void insert(int &Now,int L,int R,int pos,int num)
{
if(!Now) Now=++tot;
if(L==R){ s[Now].mx=num; s[Now].pos=L; return ;}
int Mid=(L+R)>>;
if(pos<=Mid) insert(s[Now].l,L,Mid,pos,num);
else insert(s[Now].r,Mid+,R,pos,num);
pushup(Now);
}
int merge(int x,int y,int L,int R){
if(!x||!y) return x|y;
if(L==R) { s[x].mx+=s[y].mx; return x;}
int Mid=(L+R)>>;
s[x].l=merge(s[x].l,s[y].l,L,Mid);
s[x].r=merge(s[x].r,s[y].r,Mid+,R);
pushup(x); return x;
}
void dfs(int u,int f){
for(int i=Laxt[u];i;i=Next[i]){
int v=To[i]; if(v==f) continue;
dfs(v,u);
rt[u]=merge(rt[u],rt[v],,M);
}
ans[u][]=s[rt[u]].mx; ans[u][]=s[rt[u]].pos;
}
int main()
{
int N,u,v;
scanf("%d%d",&N,&M);
rep(i,,N-){
read(u); read(v);
add(u,v); add(v,u);
}
rep(i,,N) read(A[i]),read(B[i]);
rep(i,,N) insert(rt[i],,M,A[i],B[i]);
dfs(,);
rep(i,,N) printf("%d %d\n",ans[i][],ans[i][]);
return ;
}

然后想着每一层,我先合并子树大小较小的。   即按sz排序后再合并,和上次一样,并没有优化。 7988ms

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=;
void read(int &x){
x=; char c=getchar();
while(c>''||c<'') c=getchar();
while(c>=''&&c<='') x=x*+c-'',c=getchar();
}
struct in{
int l,r,pos,mx;
in(){l=r=mx=pos=;}
}s[maxn*];
int Laxt[maxn],Next[maxn],To[maxn],cnt,M,sz[maxn];
int A[maxn],B[maxn],rt[maxn],tot,ans[maxn][];
void add(int u,int v){
Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v;
}
void pushup(int Now){
if(s[Now].l&&!s[Now].r){
s[Now].mx=s[s[Now].l].mx; s[Now].pos=s[s[Now].l].pos;
}
else if(s[Now].l&&s[Now].r&&s[s[Now].l].mx>=s[s[Now].r].mx){
s[Now].mx=s[s[Now].l].mx; s[Now].pos=s[s[Now].l].pos;
}
else s[Now].mx=s[s[Now].r].mx,s[Now].pos=s[s[Now].r].pos;
}
void insert(int &Now,int L,int R,int pos,int num)
{
if(!Now) Now=++tot;
if(L==R){ s[Now].mx=num; s[Now].pos=L; return ;}
int Mid=(L+R)>>;
if(pos<=Mid) insert(s[Now].l,L,Mid,pos,num);
else insert(s[Now].r,Mid+,R,pos,num);
pushup(Now);
}
int merge(int x,int y,int L,int R){
if(!x||!y) return x|y;
if(L==R) { s[x].mx+=s[y].mx; return x;}
int Mid=(L+R)>>;
s[x].l=merge(s[x].l,s[y].l,L,Mid);
s[x].r=merge(s[x].r,s[y].r,Mid+,R);
pushup(x); return x;
}
void dfs1(int u,int f){
sz[u]=;
for(int i=Laxt[u];i;i=Next[i]){
if(To[i]!=f) dfs1(To[i],u);
sz[u]+=sz[To[i]];
}
}
bool cmp(int w,int v){ return sz[w]<sz[v]; }
void dfs2(int u,int f){
cnt=; vector<int>G;
for(int i=Laxt[u];i;i=Next[i]){
if(To[i]!=f) G.push_back(To[i]);
}
sort(G.begin(),G.end(),cmp);
for(int i=;i<G.size();i++){
int v=G[i]; dfs2(v,u);
rt[u]=merge(rt[u],rt[v],,M);
}
ans[u][]=s[rt[u]].mx; ans[u][]=s[rt[u]].pos;
}
int main()
{
int N,u,v;
scanf("%d%d",&N,&M);
rep(i,,N-){
read(u); read(v);
add(u,v); add(v,u);
}
rep(i,,N) read(A[i]),read(B[i]);
rep(i,,N) insert(rt[i],,M,A[i],B[i]);
dfs1(,);
dfs2(,);
rep(i,,N) printf("%d %d\n",ans[i][],ans[i][]);
return ;
}

BZOJ:5457: 城市(线段树合并)(尚待优化)的更多相关文章

  1. BZOJ #5457: 城市 [线段树合并]

    线段树合并的板子题,每次从下到上合并就完事了 // by Isaunoya #include <bits/stdc++.h> using namespace std; #define re ...

  2. BZOJ 4530 LCT/线段树合并

    //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using nam ...

  3. 线段树合并 || BZOJ 5457: 城市

    题面:https://www.lydsy.com/JudgeOnline/problem.php?id=5457 题解: 线段树合并,对于每个节点维护sum(以该节点为根的子树中最大的种类和)和kin ...

  4. [BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】

    题目链接:BZOJ - 2212 题目分析 子树 x 内的逆序对个数为 :x 左子树内的逆序对个数 + x 右子树内的逆序对个数 + 跨越 x 左子树与右子树的逆序对. 左右子树内部的逆序对与是否交换 ...

  5. BZOJ.4399.魔法少女LJJ(线段树合并)

    BZOJ 注意\(c\leq7\)→_→ 然后就是裸的权值线段树+线段树合并了. 对于取\(\max/\min\)操作可以直接区间修改清空超出范围的值,然后更新到对应位置上就行了(比如对\(v\)取\ ...

  6. BZOJ.5461.[PKUWC2018]Minimax(DP 线段树合并)

    BZOJ LOJ 令\(f[i][j]\)表示以\(i\)为根的子树,权值\(j\)作为根节点的概率. 设\(i\)的两棵子树分别为\(x,y\),记\(p_a\)表示\(f[x][a]\),\(p_ ...

  7. BZOJ.3307.雨天的尾巴(dsu on tree/线段树合并)

    BZOJ 洛谷 \(dsu\ on\ tree\).(线段树合并的做法也挺显然不写了) 如果没写过\(dsu\)可以看这里. 对修改操作做一下差分放到对应点上,就成了求每个点子树内出现次数最多的颜色, ...

  8. BZOJ.3653.谈笑风生(长链剖分/线段树合并/树状数组)

    BZOJ 洛谷 \(Description\) 给定一棵树,每次询问给定\(p,k\),求满足\(p,a\)都是\(b\)的祖先,且\(p,a\)距离不超过\(k\)的三元组\(p,a,b\)个数. ...

  9. BZOJ.5417.[NOI2018]你的名字(后缀自动机 线段树合并)

    LOJ 洛谷 BZOJ 考虑\(l=1,r=|S|\)的情况: 对\(S\)串建SAM,\(T\)在上面匹配,可以得到每个位置\(i\)的后缀的最长匹配长度\(mx[i]\). 因为要去重,对\(T\ ...

随机推荐

  1. Memcached stats items 命令

    Memcached stats items 命令用于显示各个 slab 中 item 的数目和存储时长(最后一次访问距离现在的秒数). 语法: stats items 命令的基本语法格式如下: sta ...

  2. 微信开发中使用curl忽略https证书

    http://blog.csdn.net/ljh504429906/article/details/51103519 微信开发中需要使用http及https的post与get请求实现api的调用.   ...

  3. Oracle 冷备份详解【实战案例】

    Oracle 冷备份详解 --准备工作 select * from v$database; select file_name from dba_data_files; create tablespac ...

  4. program发展史及以后预测

    三个阶段:第一个阶段是1950年代到1960年代,是程序设计阶段,基本是个体手工劳动的生产方式.这个时期,一个程序是为一个特定的目的而编制的,软件的通用性是很有限的,软件往往带有强烈的个人色彩.早期的 ...

  5. 25.大白话说java并发工具类-CountDownLatch,CyclicBarrier,Semaphore,Exchanger

    1. 倒计时器CountDownLatch 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种的业务场景下,通常可以使用Thread类的join ...

  6. linux下如何安装lua

    1.下载lua包并解压 wget -c http://www.lua.org/ftp/lua-5.3.0.tar.gz  tar zxvf lua-5.3.0.tar.gz 2.下载libreadli ...

  7. UVA-1611 Crane (构造)

    题目大意:给一个1~n的序列,每次操作可以把长度为偶数的序列交换前一半和后一半的位置.求出将这个序列变成升序的步骤. 题目分析:构造求解. 代码如下: # include<iostream> ...

  8. 详解offset

    offset offset 译为“偏移量”,是javascript很重要的一个概念.涉及到便宜量的主要有offsetLeft.offsetTop.offHeight.offsetWidth这四个属性还 ...

  9. 使用libimobiledevice + ifuse提取iOS沙盒文件

    简介 libimobiledevice:一个开源包,可以让Linux支持连接iPhone/iPod Touch等iOS设备. Git仓库: https://github.com/libimobiled ...

  10. shiro:10个过滤器;10个jsp标签;5个@注解

    10个过滤器 过滤器简称 对应的java类 anon org.apache.shiro.web.filter.authc.AnonymousFilter authc org.apache.shiro. ...