2014 ICPC---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.
For the first test case, the relief grain in the 1st village is {1, 2}, and the relief grain in the 2nd village is {1, 2, 2}.
方法就是打标记。线段树维护的是颜色。也就是维护的是[a,b]就是维护a颜色到b颜色某种颜色出现的最多次数。
假设我们处理的是序列而不是树吧。比如我们要把区间[x,y]图成a颜色.那么我们就在x出加个标记a。在y+1就标记-a。
多个标记用邻接表连起来就行了。然后从序列的最左端处理到最右端先把所有标记更新到线段树里。a则a颜色+1。
-a则在线段树将a颜色-1.然后再询问线段树里出现最多的次数就是序列该位置的次数最多的颜色了。相当于递推的思想吧。知道了x位置的颜色线段树.x+1位置的颜色线段树 无非是多了一些颜色或者少了某些颜色。多了减掉。少了的加上就是自己这个位置上的了。这样做之所以高效的原因是标记的是区间的端点而不是区间类的每一个元素。总的 时间复杂度m*log(n)*log(c)。m为询问数。n为结点数。c为颜色种数。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define N 100005
#define M 200005
using namespace std;
int n,q,cnt,sz;
int fa[N][],deep[N],size[N],head[N];
int pos[N],belong[N];
bool vis[N];
int mv[],leaf[],h[M]; struct data
{
int to,next;
} e[M],w[M*]; void insert(int u,int v)
{
e[++cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
e[++cnt].to=u;
e[cnt].next=head[v];
head[v]=cnt;
} void init()
{
cnt=;
sz=;
memset(deep,,sizeof(deep));
memset(head,,sizeof(head));
memset(vis,,sizeof(vis));
memset(h,,sizeof(h));
memset(mv,,sizeof(mv));
for(int i=; i<n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
insert(x,y);
}
} void dfs1(int x)
{
size[x]=;
vis[x]=;
for(int i=; i<=; i++)
{
if(deep[x]<(<<i))break;
fa[x][i]=fa[fa[x][i-]][i-];//倍增处理祖先信息
}
for(int i=head[x]; i; i=e[i].next)
{
if(vis[e[i].to])continue;
deep[e[i].to]=deep[x]+;
fa[e[i].to][]=x;
dfs1(e[i].to);
size[x]+=size[e[i].to];
}
} void dfs2(int x,int chain)
{
int k=;
sz++;
pos[x]=sz;//分配x结点在线段树中的编号
belong[x]=chain;
for(int i=head[x]; i; i=e[i].next)
if(deep[e[i].to]>deep[x]&&size[e[i].to]>size[k])
k=e[i].to;//选择子树最大的儿子继承重链
if(k==)return;
dfs2(k,chain);
for(int i=head[x]; i; i=e[i].next)
if(deep[e[i].to]>deep[x]&&k!=e[i].to)
dfs2(e[i].to,e[i].to);//其余儿子新开重链
} void build(int rt,int l,int r)//建线段树
{
if(l==r)
{
leaf[l]=rt;
return;
}
int mid=(l+r)>>;
build(rt<<,l,mid);
build(rt<<|,mid+,r);
} void update(int rt,int c)
{
if(c>) c=;
else c=-;
mv[rt]+=c;
while(rt>)
{
rt>>=;
mv[rt]=max(mv[rt<<],mv[rt<<|]);
}
} int qu(int L,int R,int rt)
{
int ls,rs,mid;
if(mv[rt]==)
return ;
while(L<R)
{
ls=rt<<,rs=ls|,mid=(L+R)>>;
if(mv[rs]>mv[ls])
L=mid+,rt=rs;
else
R=mid,rt=ls;
}
return L;
} void adde(int x,int d)
{
w[++cnt].to=d;
w[cnt].next=h[x];
h[x]=cnt;
} void uppath(int u,int v,int d)
{
int f1=belong[u],f2=belong[v];
while(f1!=f2)
{
if(deep[f1]<deep[f2])
swap(f1,f2),swap(u,v);
adde(pos[f1],d);
adde(pos[u]+,-d);
u=fa[f1][],f1=belong[u];
}
if(deep[u]>deep[v])
swap(u,v);
adde(pos[u],d);
adde(pos[v]+,-d);
} void solve()
{
build(,,);
cnt=;
for(int i=; i<=q; i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
uppath(x,y,z);
}
int ans[N];
for(int i=;i<=n;i++)
{
for(int j=h[i];j;j=w[j].next)
{
update(leaf[abs(w[j].to)],w[j].to);
}
ans[i]=qu(,,);
}
for(int i=;i<=n;i++)
{
printf("%d\n",ans[pos[i]]);
}
} int main()
{
while(scanf("%d%d",&n,&q)&&(n+q))
{
init();
dfs1();
dfs2(,);
solve();
}
return ;
}
高手的代码:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int maxn=;
int fa[maxn],siz[maxn],son[maxn],w[maxn],p[maxn],dep[maxn],fp[maxn],Rank[maxn],ans[maxn];
//fa为父节点,siz为子节点中siz最大的,dep为深度,son为重儿子,w表示在线段树中的位置
int num[maxn<<],ppp[maxn<<];
int tree_id,n;
vector<int>G[maxn];
void dfs1(int u,int ff,int deep){
son[u]=;fa[u]=ff;siz[u]=;dep[u]=deep;
for(unsigned int i=;i<G[u].size();i++){
int v=G[u][i];
if(v==ff) continue;
dfs1(v,u,deep+);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int ff){
w[u]=++tree_id;p[u]=ff;Rank[w[u]]=u;
if(son[u]) dfs2(son[u],ff);
else return ;
for(unsigned int i=;i<G[u].size();i++){
int v=G[u][i];
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
void pushup(int node){
if(num[node<<]>=num[node<<|]){
num[node]=num[node<<];ppp[node]=ppp[node<<];
}else{
num[node]=num[node<<|];ppp[node]=ppp[node<<|]; }
}
void buildtree(int le,int ri,int node){
if(le==ri){
num[node]=;ppp[node]=le;
return ;
}
int t=(le+ri)>>;
buildtree(le,t,node<<);
buildtree(t+,ri,node<<|);
pushup(node);
}
void update(int pos,int val,int le,int ri,int node){
if(le==ri){
num[node]+=val;
return ;
}
int t=(le+ri)>>;
if(pos<=t) update(pos,val,le,t,node<<);
else update(pos,val,t+,ri,node<<|);
pushup(node);
}
struct nnnn{
int u,v,z;
nnnn(int a,int b,int c){u=a;v=b;z=c;}
};
vector<nnnn>GG;
vector<int>GGG[maxn];
void getsum(int u,int v,int z){
int f1=p[u],f2=p[v];
while(f1!=f2){
if(dep[f1]<dep[f2]){
swap(f1,f2);
swap(u,v);
}
GG.push_back(nnnn(w[f1],w[u],z));
u=fa[f1];f1=p[u];
}
if(dep[u]>dep[v]) swap(u,v);
GG.push_back(nnnn(w[u],w[v],z));
}
int main(){
int u,v,q,op,z;
while(scanf("%d%d",&n,&q)!=-){
if(n==&&q==) break;
for(int i=;i<maxn;i++) G[i].clear(),GGG[i].clear();
GG.clear();
memset(son,,sizeof(son));tree_id=;
for(int i=;i<n-;i++){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(,,);
dfs2(,);
int max1=;
for(int i=;i<=q;i++){
scanf("%d%d%d",&u,&v,&z);
max1=max(max1,z);
getsum(u,v,z);
}
if(q==){
for(int i=;i<=n;i++) printf("0\n");
continue;
}
buildtree(,max1,);
for(int i=;i<GG.size();i++){
nnnn ne=GG[i];
GGG[ne.u].push_back(ne.z);
GGG[ne.v+].push_back(-ne.z);
}
for(int i=;i<=n;i++){
for(int j=;j<GGG[i].size();j++){
int ttt=GGG[i][j];
if(ttt<) update(-ttt,-,,max1,);
else update(ttt,,,max1,);
}
if(num[]==) ans[Rank[i]]=;
else ans[Rank[i]]=ppp[];
}
for(int i=;i<=n;i++) printf("%d\n",ans[i]);
}
return ;
}
2014 ICPC---Relief grain(树链剖分)的更多相关文章
- hdu 5029 Relief grain(树链剖分+线段树)
题目链接:hdu 5029 Relief grain 题目大意:给定一棵树,然后每次操作在uv路径上为每一个节点加入一个数w,最后输出每一个节点个数最多的那个数. 解题思路:由于是在树的路径上做操作, ...
- HDU 5029 Relief grain 树链剖分打标记 线段树区间最大值
Relief grain Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid= ...
- HDU 5029 Relief grain --树链剖分第一题
题意:给一棵树,每次给两个节点间的所有节点发放第k种东西,问最后每个节点拿到的最多的东西是哪种. 解法:解决树的路径上的修改查询问题一般用到的是树链剖分+线段树,以前不会写,后来学了一下树链剖分,感觉 ...
- hdu_5029_relief grain(树链剖分)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5029 题意:给你一个树,然后给你两点,将这两点之间的点涂上颜色,问涂色最多的那个颜色是什么,如果数量相 ...
- HDU5029--Relief grain (树链剖分+线段树 )
题意:n个点构成的无根树,m次操作, 对于操作 x y z, 表示 x 到 y 路径上的 每个点 加一个 z 数字,可重复加.最后输出每个点 加的次数最多的那个数字,如果没有输出0. 赤裸裸的树链剖分 ...
- HDU 4897 Little Devil I(树链剖分)(2014 Multi-University Training Contest 4)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4897 Problem Description There is an old country and ...
- 2019 icpc南昌全国邀请赛-网络选拔赛J题 树链剖分+离线询问
链接:https://nanti.jisuanke.com/t/38229 题意: 给一棵树,多次查询,每次查询两点之间权值<=k的边个数 题解: 离线询问,树链剖分后bit维护有贡献的位置即可 ...
- 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)
Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...
- 树链剖分+线段树+离线(广州网选赛第八题hdu5029)
http://acm.hdu.edu.cn/showproblem.php?pid=5029 Relief grain Time Limit: 10000/5000 MS (Java/Others) ...
随机推荐
- WebApi系列~StringContent参数需要添加MetaType对象
回到目录 对于api调用已经很多见了,在客户端去post一个请求到API服务端也是经常见到,但有时不注意,可能会引起一些问题,如为一个HttpContent参数进行赋值时,如果使用StringCont ...
- Mybatis入门例子
Mybatis是轻量级的持久化框架,的确上手非常快. Mybatis大体上的思路就是由一个总的config文件配置全局的信息,比如mysql连接信息等.然后再mapper中指定查询的sql,以及参数和 ...
- [Spring框架]Spring开发实例: XML+注解.
前言: 本文为自己学习Spring记录所用, 文章内容包括Spring的概述已经简单开发, 主要涉及IOC相关知识, 希望能够对新入门Spring的同学有帮助, 也希望大家一起讨论相关的知识. 一. ...
- Atitti 跨语言异常的转换抛出 java js
Atitti 跨语言异常的转换抛出 java js 异常的转换,直接反序列化为json对象e对象即可.. Js.没有完整的e机制,可以参考java的实现一个stack层次机制的e对象即可.. 抛出Ru ...
- atitit 业务 触发器原理. 与事件原理 docx
atitit 业务 触发器原理. 与事件原理 docx 1.1. 呵呵,你需要需要一个业务 触发器..1 1.2. 触发器/事件/中断的原理1 1.3. Io 硬件中断的原理( 中断的低层有cpu轮询 ...
- javascript中this指向
在简单函数中,this是指向当前对象,可用来获取当前对象某个属性,但随着函数变复杂,this很多情况不指向当前对象,而是指向window. 1.在独立调用函数中,具有全局执行环境,this指向wind ...
- 每天一个linux命令(16):which命令
我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索: which 查看可执行文件的位置. whereis 查看文件的位置. ...
- Java EE开发平台随手记6——Mybatis扩展4
这篇博客中来说一下对Mybatis动态代理接口方式的扩展,对于Mybatis动态代理接口不熟悉的朋友,可以参考前一篇博客,或者研读Mybatis源码. 扩展11:动态代理接口扩展 我们知道,真正在My ...
- hibernate(六)一对一映射
关系映射是指对象之间的关系,并不是指数据库的关系,关系映射是解决当对象处于以下关系之一时,数据库表该如何映射的问题 (一)一对一单向外键关联 1.注解方式配置 创建一个Husband类和Wife类 H ...
- poj 2195 Going Home
/* 做网络流的题建图真的是太重要了! 本题是将人所在的位置和房子所在的位置建立边的联系,其中man到house这一条边的流量为 1, 费用为两者的距离 而方向边的流量为 0, 费用为正向边的相反数( ...