树链剖分+线段树+离线(广州网选赛第八题hdu5029)
http://acm.hdu.edu.cn/showproblem.php?pid=5029
Relief grain
We can regard the kingdom as a tree with n nodes and each node stands for a village. The distribution of the relief grain is divided into m phases. For each phases, the RRC will choose a path of the tree and distribute some relief grain of a certain type for
every village located in the path.
There are many types of grains. The RRC wants to figure out which type of grain is distributed the most times in every village.
For each test case, the first line contains two integer n and m indicating the number of villages and the number of phases.
The following n-1 lines describe the tree. Each of the lines contains two integer x and y indicating that there is an edge between the x-th village and the y-th village.
The following m lines describe the phases. Each line contains three integer x, y and z indicating that there is a distribution in the path from x-th village to y-th village with grain of type z. (1 <= n <= 100000, 0 <= m <= 100000, 1 <= x <= n, 1 <= y <= n,
1 <= z <= 100000)
The input ends by n = 0 and m = 0.
is no relief grain in a village, just output 0.
2 4
1 2
1 1 1
1 2 2
2 2 2
2 2 1
5 3
1 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3
0 0
1
2
2
3
3
0
2
题意:给出一棵树,然后有一系列的操作,每次操作有a,b,c代表在a到b的路径上的每个点都给一个c类型的数字;最后问所有操作完成后树上的每个节点拥有的数量最多的类型是多少,如果存在多个输出较小类型的数字;
分析:首先这种在树上的操作,很容易想到是树链剖分的题目,但是具体该怎么写呢:先不考虑树的问题,可以把题意抽象出一个普通的连续区间【1,n】,然后在不同区间进行分配东西,最后问每个点的结果,对于区间【L,R】上分配一个数字Z,那么就在L位置上标记+Z,代表从此时以后的每个节点都拥有一个Z,然后在R+1的位置上标记一个-Z,代表从该节点开始没有分配Z这个数字;所以先把m个操作记录下来,对于每个标记的节点,可以用一个vector容器记录所标记的东西,接下来我们可以建立一个权值线段树区间【1,100000】;每个点分别代表数字Z的类型,px数组代表每个类型数字当前出现的次数;tree[i].maxi代表i区间的最大值,从左向右遍历区间【1,n】,对于每个节点更新px的值,如果标记是+Z,则px[z]++;否则px[-z]--;然后query即可;
树链剖分也是同样的道理,轻重链的划分不详说了,对于一个树上的两点<u,v>,把它转化为多条连续的子链利用线段树操作即可;具体程序如下:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include"stdio.h"
#include"string.h"
#include"iostream"
#include"map"
#include"string"
#include"queue"
#include"stdlib.h"
#include"math.h"
#define M 110009
#define eps 1e-10
#define inf 1000000000
#define mod 1000000000
#define INF 1000000000
using namespace std;
struct node
{
int u,v,next;
}edge[M*2];
struct Lnode
{
int v;
Lnode(int vv)
{
v=vv;
}
};
vector<Lnode>e[M];
int t,pos,head[M],son[M],fa[M],num[M],top[M],ID,deep[M],p[M],fp[M],px[M];
void init()
{
t=pos=0;
memset(head,-1,sizeof(head));
memset(son,-1,sizeof(son));
memset(fa,-1,sizeof(fa));
}
void add(int u,int v)
{
edge[t].u=u;
edge[t].v=v;
edge[t].next=head[u];
head[u]=t++;
}
void dfs(int u,int f,int d)
{
deep[u]=d;
fa[u]=f;
num[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v==f)continue;
dfs(v,u,d+1);
num[u]+=num[v];
if(son[u]==-1||num[son[u]]<num[v])
son[u]=v;
}
}
void getpos(int u,int sp)
{
top[u]=sp;
p[u]=pos++;
fp[p[u]]=u;
if(son[u]==-1)return;
getpos(son[u],sp);
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v==fa[u]||v==son[u])continue;
getpos(v,v);
}
}
/**********以上是划分轻重链**************/
struct Tree
{
int l,r,maxi;
}tree[M*4];
void make(int l,int r,int i)//线段树建树操作
{
tree[i].l=l;
tree[i].r=r;
if(l==r)
{
tree[i].maxi=0;
return ;
}
int mid=(l+r)/2;
make(l,mid,i*2);
make(mid+1,r,i*2+1);
tree[i].maxi=max(tree[i*2].maxi,tree[i*2+1].maxi);
}
void updata(int p,int q,int i)//单点更新操作
{
if(tree[i].l==p&&tree[i].r==p)
{
tree[i].maxi=q;
return;
}
int mid=(tree[i].l+tree[i].r)/2;
if(p<=mid)updata(p,q,i*2);
else updata(p,q,i*2+1);
tree[i].maxi=max(tree[i*2].maxi,tree[i*2+1].maxi);
}
void query(int l,int r,int i)//区间查找最大值对应的标,若有多个查找编号最小的记录到ID中
{
if(tree[i].maxi<tree[1].maxi)
return;
if(tree[i].l==tree[i].r)
{
if(tree[i].l<ID)
ID=tree[i].l;
return;
}
int mid=(tree[i].l+tree[i].r)/2;
if(r<=mid)
query(l,r,i*2);
else if(l>mid)
query(l,r,i*2+1);
else
{
query(l,mid,i*2);
query(mid+1,r,i*2+1);
}
}
void Insert(int u,int v,int w)//树与线段树的转化操作
{
int f1=top[u];
int f2=top[v];
while(f1!=f2)
{
if(deep[f1]<deep[f2])
{
swap(f1,f2);
swap(u,v);
}
e[p[f1]].push_back(Lnode(w));
e[p[u]+1].push_back(Lnode(-w));
u=fa[f1];
f1=top[u];
}
if(u==v)
{
e[p[u]].push_back(Lnode(w));
e[p[u]+1].push_back(Lnode(-w));
return;
}
if(deep[u]>deep[v])
swap(u,v);
e[p[u]].push_back(Lnode(w));
e[p[v]+1].push_back(Lnode(-w));
return;
}
int s[M];
int main()
{
int n,m,i,j,a,b,c,u,v;
while(scanf("%d%d",&n,&m),m||n)
{
init();
for(i=0;i<=n;i++)
e[i].clear();
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,1,1);
getpos(1,1);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
Insert(a,b,c);
}
make(1,100000,1);
memset(px,0,sizeof(px));
for(i=0;i<pos;i++)
{
for(j=0;j<(int)e[i].size();j++)
{
int v=e[i][j].v;
if(v>0)
{
px[v]++;
updata(v,px[v],1);
}
else
{
px[-v]--;
updata(-v,px[-v],1);
}
}
if(tree[1].maxi==0)
{
s[fp[i]]=0;
continue;
}
ID=100000;
query(1,100000,1);
s[fp[i]]=ID;
//printf("%d\n",ID);
}
for(i=1;i<=n;i++)
printf("%d\n",s[i]);
}
return 0;
}
树链剖分+线段树+离线(广州网选赛第八题hdu5029)的更多相关文章
- 2019西北工业大学程序设计创新实践基地春季选拔赛 I Chino with Rewrite (并查集+树链剖分+线段树)
链接:https://ac.nowcoder.com/acm/contest/553/I 思路:离线整棵树,用并查集维护下联通的情况,因为值只有60个,用2的x(1<=x<=60)次方表示 ...
- 洛谷P4092 [HEOI2016/TJOI2016]树 并查集/树链剖分+线段树
正解:并查集/树链剖分+线段树 解题报告: 传送门 感觉并查集的那个方法挺妙的,,,刚好又要复习下树剖了,所以就写个题解好了QwQ 首先说下并查集的方法趴QwQ 首先离线,读入所有操作,然后dfs遍历 ...
- 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- 【bzoj1959】[Ahoi2005]LANE 航线规划 树链剖分+线段树
题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
随机推荐
- 关于Cocos2d-x的动作和动画
1.动作,在cocos2d-x中有非常多种的动作,各种移动,旋转,缩放,淡入淡出....等等非常多,但是这些动作只是作用于节点,最常作用于的就是精灵节点.而且我们可以把很多个动作放进一个Sequenc ...
- C++ 判断目录是否存在并新建目录
http://blog.csdn.net/u012005313/article/details/50688257 #include <io.h> #include <string&g ...
- Spring bean的初始化及销毁
Spring bean的几个属性:scope.init-method.destroy-method.depends-on等. Scope 在Spring容器中是指其创建的Bean对象相对于其他Bean ...
- LogCat大量Unexpected value from nativeGetEnabledTags: 0
在执行模拟器的时候.LogCat 输出非常多Unexpected value from nativeGetEnabledTags: 0 提示.导致非常多本来须要输出的信息被瞬间覆盖了,查询后得知是sd ...
- Onject.Instantiate实例
该函数有两个函数原型: Object Instantiate(Object original,Vector3 position,Quaternion rotation); Onject Instant ...
- MVC+LINQToSQL的Repository模式之(二)数据基类
namespace Data.TEST{ /// <summary> /// 数据操作基类 /// </summary> public abstract ...
- 不定义JQuery插件 不要说会JQuery
二.普及JQuery知识 知识1:用JQuery写插件时,最核心的方法有如下两个: $.extend(object) 可以理解为JQuery 添加一个静态方法. $.fn.extend(object) ...
- 详解MathType中如何插入特殊符号
在论文写作中,经常会用到一些特殊符号,MathType公式编辑器支持插入特殊符号,并且数量繁多,可以满足用户的需求.本教程将详解MathType如何插入特殊符号. MathType中插入特殊符号的操作 ...
- 这款Office密码破解工具,无坚不摧!
你是否曾经陷入过这样的尴尬:因为忘记Word文档密码去找了一个Word密码破解工具,接着又忘记Excel文档密码去找了一个专门破击Excel的工具,那么如果忘记PowerPoint.Outlook.P ...
- linux中,ssh实现免密自动登录到远程主机,ssh信任的实现
需求描述: 平时使用ssh的时候,一般使用ssh都是通过用户名和密码登录到远程主机上, 然后执行一些命令,远程登录过程中,需要手动的输入密码(提示输入密码之后), 但是,在实际的应用过程中,涉及到让脚 ...