COJ 0346 WZJ的旅行(二)更新动态树分治版本
| WZJ的旅行(二) |
| 难度级别:D; 运行时间限制:3000ms; 运行空间限制:51200KB; 代码长度限制:2000000B |
|
试题描述
|
|
时隔多日,WZJ又来到了幻想国旅行。幻想国由N个城市组成,由于道路翻修,只有N-1条双向道路可以通行,第i条双向道路从ui连接到vi,距离为wi。但这N-1条道路竟然连接了整个国家,每两个城市之间都有一条道路! WZJ知道这里景点很多,所以他想从城市s出发到城市t,旅游所有沿途的城市。WZJ想起到锻炼作用,但又不想太累,所以城市s到城市t的距离必须在L到R之间。另外WZJ规定s必须小于t,你能帮助他统计有多少对城市(s,t)符合要求吗? |
|
输入
|
|
第一行为三个正整数N,L,R。
接下来N-1行每行为三个正整数ui,vi,wi。 |
|
输出
|
|
输出多少对城市(s,t)符合要求。
|
|
输入示例
|
|
5 3 6
1 2 3 2 3 3 3 4 2 4 5 1 |
|
输出示例
|
|
6
|
|
其他说明
|
|
城市对(1,2)、(2,3)、(1,3)、(2,4)、(2,5)、(3,5)均符合要求,共计6对
1<=N<=100000 1<=L<=R<=10^9 1<=ui,vi<=N 1<=wi<=1000 |
题解:会写点分治了。。。
首先补集转换,不在同一个子树的 = 总的 - 在同一个子树的,那么就是求路径两段在同一个子树的,dfs一遍排序再金鸡独立大法求前缀,转成区间,然后就没了。
意会一下。。。(逃。。。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define PAU putchar(' ')
#define ENT putchar('\n')
using namespace std;
const int maxn=+,inf=-1u>>;
struct ted{int x,y,w;ted*nxt;}adj[maxn<<],*fch[maxn],*ms=adj;
void add(int w,int y,int x){
*ms=(ted){x,y,w,fch[x]};fch[x]=ms++;
*ms=(ted){y,x,w,fch[y]};fch[y]=ms++;
return;
}
bool vis[maxn];
int L,R,CG=,siz[maxn],f[maxn],n,size;
void findcg(int x,int fa){
int mxs=-inf;siz[x]=;
for(ted*e=fch[x];e;e=e->nxt){
int v=e->y;if(v!=fa&&!vis[v]){
findcg(v,x);siz[x]+=siz[v];
mxs=max(mxs,siz[v]);
}
}f[x]=max(mxs,size-siz[x]);
if(f[x]<f[CG])CG=x;return;
}
long long ans;
int A[maxn],dep[maxn],cnt;
void dfs(int x,int fa,int dist){
A[cnt++]=dist;
for(ted*e=fch[x];e;e=e->nxt){
int v=e->y;if(v!=fa&&!vis[v])dfs(v,x,dist+e->w);
}return;
}
long long cal(int x,int base){
cnt=;dfs(x,,base);long long res=;
sort(A,A+cnt);
int l=,r=cnt-;while(l<r)if(A[l]+A[r]>R)r--;else res+=r-l++;
l=;r=cnt-;while(l<r)if(A[l]+A[r]>=L)r--;else res-=r-l++;
return res;
}
void solve(int x){
vis[x]=true;ans+=cal(x,);
for(ted*e=fch[x];e;e=e->nxt){
int v=e->y;if(!vis[v]){
ans-=cal(v,e->w);
f[CG=]=inf;size=siz[v];findcg(v,);
solve(CG);
}
}return;
}
inline int read(){
int x=,sig=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') sig=-;ch=getchar();}
while(isdigit(ch)) x=*x+ch-'',ch=getchar();
return x*=sig;
}
inline void write(long long x){
if(x==){putchar('');return;}if(x<) putchar('-'),x=-x;
int len=;long long buf[];while(x) buf[len++]=x%,x/=;
for(int i=len-;i>=;i--) putchar(buf[i]+'');return;
}
void init(){
n=read();L=read();R=read();
for(int i=;i<n;i++)add(read(),read(),read());
f[CG=]=inf;size=n;findcg(,);
solve(CG);write(ans);
return;
}
void work(){
return;
}
void print(){
return;
}
int main(){
init();work();print();return ;
}
当然窝萌还可以写动态树分治对不对,维护两个treap就是常数有点大耶。
要注意一点:cal函数只需要query就行了,不需要重新计算一遍!!!
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<ctime>
#define PAU putchar(' ')
#define ENT putchar('\n')
#define CH for(int d=0;d<2;d++)if(ch[d])
using namespace std;
const int maxn=+,maxq=+,maxnode=+,maxm=+,inf=-1u>>;
struct node{
node*ch[];int r,siz,v;
void init(){r=rand();siz=;ch[]=ch[]=NULL;return;}
void update(){siz=;CH{siz+=ch[d]->siz;}return;}
}treap[maxnode],*nodecnt=treap,*cha[maxn],*tre[maxn];
node*newnode(){node*x=nodecnt++;x->init();return x;}
void rotate(node*&x,int d){
node*k=x->ch[d^];x->ch[d^]=k->ch[d];k->ch[d]=x;x->update();k->update();x=k;return;
}
void insert(node*&x,int v){
if(!x)x=newnode(),x->v=v;
else{int d=v>x->v;insert(x->ch[d],v);
if(x->r<x->ch[d]->r)rotate(x,d^);else x->update();
}return;
}
int find(node*x,int v){
if(!x)return ;
if(v<=x->v)return find(x->ch[],v);
else return (x->ch[]?x->ch[]->siz:)++find(x->ch[],v);
}
struct ted{int x,y,w;ted*nxt;}adj[maxm],*fch[maxn],*ms=adj;
void add(int x,int y,int w){
*ms=(ted){x,y,w,fch[x]};fch[x]=ms++;
*ms=(ted){y,x,w,fch[y]};fch[y]=ms++;
return;
}
int mi[maxq][],Log[maxq],dep[maxn],pos[maxn],cnt;
void build(int x,int fa,int dis){
mi[++cnt][]=dep[x]=dis;pos[x]=cnt;
for(ted*e=fch[x];e;e=e->nxt){
int v=e->y;if(v!=fa)build(v,x,dis+e->w),mi[++cnt][]=dep[x];
}return;
}
void initrmq(){
Log[]=-;for(int i=;i<=cnt;i++)Log[i]=Log[i>>]+;
for(int j=;(<<j)<=cnt;j++)
for(int i=;i+(<<j)-<=cnt;i++)
mi[i][j]=min(mi[i][j-],mi[i+(<<j-)][j-]);return;
}
int dist(int x,int y){
int ans=dep[x]+dep[y];x=pos[x];y=pos[y];if(x>y)swap(x,y);
int k=Log[y-x+];return ans-*min(mi[x][k],mi[y-(<<k)+][k]);
}
int CG,f[maxn],size,siz[maxn],fa[maxn];bool vis[maxn];
void findcg(int x,int fa){
siz[x]=;int mxs=;
for(ted*e=fch[x];e;e=e->nxt){
int v=e->y;if(v!=fa&&!vis[v]){
findcg(v,x);siz[x]+=siz[v];mxs=max(mxs,siz[v]);
}
}f[x]=max(mxs,size-siz[x]);if(f[x]<f[CG])CG=x;return;
}
void dfs(int x,int fa){
siz[x]=;
for(ted*e=fch[x];e;e=e->nxt){
int v=e->y;if(v!=fa&&!vis[v])dfs(v,x),siz[x]+=siz[v];
}return;
}
void solve(int x=CG){
vis[x]=true;
for(ted*e=fch[x];e;e=e->nxt){
int v=e->y;if(!vis[v]){
dfs(v,x);f[CG=]=size=siz[v];findcg(v,x);fa[CG]=x;solve();
}
}return;
}
void update(int x){
insert(tre[x],);
for(int ret=x;fa[x];x=fa[x]){
int d=dist(ret,fa[x]);
insert(tre[fa[x]],d);insert(cha[x],d);
}return;
}
int k;
int query(int x){
int ans=find(tre[x],k);
for(int ret=x;fa[x];x=fa[x]){
int d=dist(ret,fa[x]);
ans+=find(tre[fa[x]],k-d)-find(cha[x],k-d);
}return ans;
}
int n,L,R;
int cal(int t){
k=t+;int ans=;for(int i=;i<=n;i++)ans+=query(i);return ans;
}
inline int read(){
int x=,sig=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')sig=-;ch=getchar();}
while(isdigit(ch))x=*x+ch-'',ch=getchar();
return x*=sig;
}
inline void write(int x){
if(x==){putchar('');return;}if(x<)putchar('-'),x=-x;
int len=,buf[];while(x)buf[len++]=x%,x/=;
for(int i=len-;i>=;i--)putchar(buf[i]+'');return;
}
void init(){
srand(time());
n=read();L=read(),R=read();int x,y;
for(int i=;i<n;i++)x=read(),y=read(),add(x,y,read());build(,,);initrmq();
f[CG=]=size=n;findcg(,);solve();for(int i=;i<=n;i++)update(i);
write((cal(R)-cal(L-))>>);
return;
}
void work(){
return;
}
void print(){
return;
}
int main(){init();work();print();return ;}
COJ 0346 WZJ的旅行(二)更新动态树分治版本的更多相关文章
- 点分治Day2 动态树分治
蒟蒻Ez3real冬令营爆炸之后滚回来更新blog... 我们看一道题 bzoj3924 ZJOI2015D1T1 幻想乡战略游戏 给一棵$n$个点的树$(n \leqslant 150000)$ 点 ...
- 洛谷P4719 【模板】"动态 DP"&动态树分治
[模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...
- 【Learning】 动态树分治
简介 动态树分治整体上由点分治发展而来. 点分治是统计树上路径,而动态树分治用来统计与点有关的树上路径,比如多次询问某一些点到询问点的距离和. 前置知识就是点分治. 做法 众所周知,点分树(点分治中重 ...
- 【xsy2818】 最近点 动态树分治+可持久化线段树
题目大意:给你一颗n个节点的树,最初点集S为空. 有m次操作:往当前点集S中加入/删除一个点,询问点x至集合S中任意点的最小距离,回到第t次修改点集的操作后的状态. 数据范围:$n,m≤10^5$ 我 ...
- 【BZOJ3730】震波 动态树分治+线段树
[BZOJ3730]震波 Description 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土 ...
- COJ 0349 WZJ的旅行(五)
WZJ的旅行(五) 难度级别:E: 运行时间限制:3000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 WZJ又要去旅行了T^T=0.幻想国由N个城市组成,由于道 ...
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆
[BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...
- 【BZOJ4372】烁烁的游戏 动态树分治+线段树
[BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距 ...
- 【BZOJ4317】Atm的树 动态树分治+二分+线段树
[BZOJ4317]Atm的树 Description Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径 ...
随机推荐
- Apple-Watch开发1
Communicating between the iOS app and the Watch Extension There are four scenarios where an app and ...
- git 指令汇总
学习git过程中整理的笔记: git add 添加文件到暂存区: git commit -m "更改说明" 提交文件更改: git status 查看当前文件状态: git dif ...
- kissy
<!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...
- Android 四大组件之service与Broadcast
Android 四大组件之一:service: Service有五个生命周期:onCreat,onStartCommand, onBind,onUnbind, onDestroy 主要有绑定和非绑定两 ...
- Oracle dblink的创建及使用
在工作中遇到的情况简单说下: --首先要赋予用户创建dblink的权限.grant resource to ods_nwsc;grant create database link to ods_nws ...
- magic_quotes_gpc、mysql_real_escape_string、addslashes的区别及用法
本篇文章,主要先重点说明magic_quotes_gpc.mysql_real_escape_string.addslashes 三个函数方法的含义.用法,并举例说明.然后阐述下三者间的区别.关系.一 ...
- iOS 事件处理机制与图像渲染过程(转)
iOS 事件处理机制与图像渲染过程 iOS RunLoop都干了什么 iOS 为什么必须在主线程中操作UI 事件响应 CALayer CADisplayLink 和 NSTimer iOS 渲染过程 ...
- Objective-C的对象模型 http://foredoomed.org/blog/2014/02/24/object-modeling-of-objective-c/
Objective-C是一门面向对象,并且在C的基础上加入了Smalltalk式的消息机制而形成的编程语言,它主要被苹果公司用于开发Mac OS X和iOS操作系统.既然Objective-C是面向对 ...
- 基于nodejs的消息中心
参考:http://t42dw.iteye.com/blog/1767013
- latex引用多篇参考文献
1.如何使连续的参考文献能够中间用破折号连起来?比如[6,7,8,9]变成[6-9]? 方法:在文档开始前加上下面的语句命令 \usepackage[numbers,sort&compress ...