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的旅行(二)更新动态树分治版本的更多相关文章

  1. 点分治Day2 动态树分治

    蒟蒻Ez3real冬令营爆炸之后滚回来更新blog... 我们看一道题 bzoj3924 ZJOI2015D1T1 幻想乡战略游戏 给一棵$n$个点的树$(n \leqslant 150000)$ 点 ...

  2. 洛谷P4719 【模板】"动态 DP"&动态树分治

    [模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...

  3. 【Learning】 动态树分治

    简介 动态树分治整体上由点分治发展而来. 点分治是统计树上路径,而动态树分治用来统计与点有关的树上路径,比如多次询问某一些点到询问点的距离和. 前置知识就是点分治. 做法 众所周知,点分树(点分治中重 ...

  4. 【xsy2818】 最近点 动态树分治+可持久化线段树

    题目大意:给你一颗n个节点的树,最初点集S为空. 有m次操作:往当前点集S中加入/删除一个点,询问点x至集合S中任意点的最小距离,回到第t次修改点集的操作后的状态. 数据范围:$n,m≤10^5$ 我 ...

  5. 【BZOJ3730】震波 动态树分治+线段树

    [BZOJ3730]震波 Description 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土 ...

  6. COJ 0349 WZJ的旅行(五)

    WZJ的旅行(五) 难度级别:E: 运行时间限制:3000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 WZJ又要去旅行了T^T=0.幻想国由N个城市组成,由于道 ...

  7. 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆

    [BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...

  8. 【BZOJ4372】烁烁的游戏 动态树分治+线段树

    [BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距 ...

  9. 【BZOJ4317】Atm的树 动态树分治+二分+线段树

    [BZOJ4317]Atm的树 Description Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径 ...

随机推荐

  1. Android 根据屏幕分辨率自动调整字体大小

    1.在oncreate 里获取手机屏幕宽和高度 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDispl ...

  2. 10.6 noip模拟试题

    更正:第三组:不存在相同的字符|str|=26,26<=n<=100 60 /* 呵呵哒~这题 正解还在研究.... 因为没有题解只有个std还在看 不过乱搞一下可以70(数据好像有问题只 ...

  3. codevs 2822爱在心中

    不想吐槽题目.... /* K bulabula 算法(好像用哪个T bulabula更简单 然而我并不会 - -) 丑陋的处理cnt: Printf时 cnt中 ans[i][0]==1 的删掉 然 ...

  4. discuz论坛几种安全策略(一)

    安全问题 最近公司准备搭建一个discuz论坛,大头让我调研一下discuz的安全策略,并提出如下几点要求: 1.防止php上传漏洞2.防止大量刷新攻击限制某个IP大量刷新某一页面导致论坛宕机3.防止 ...

  5. jetty运行maven程序(修改及时生效,不需要重启jetty程序)

    jetty:run -Djetty:port=9999

  6. HTML5 文件域+FileReader 分段读取文件并上传到服务器(六)

    说明:使用Ajax方式上传,文件不能过大,最好小于三四百兆,因为过多的连续Ajax请求会使后台崩溃,获取InputStream中数据会为空,尤其在Google浏览器测试过程中. 1.简单分段读取文件为 ...

  7. PictureBox内的图片拖动功能

    当 PictureBox内的图片太大,超过PictureBox边框时可以用下面的方法来实现,   通过重绘来实现 :   Code bool wselected = false;  Point p = ...

  8. Servlet(三)

    重定向 服务器向浏览器发送一个302状态码以及一个Location消息头(该消息头的值是一个地址,称之为重定向地址),浏览器收到后会立即向重定向的地址发出请求,使用相应对象的API方法实现(respo ...

  9. linux负载均衡

    1.linux lvs nat实现负载均衡 添加两块网卡并开启路由管道 > /proc/sys/net/ipv4/ip_forward //开始路由管道 安装ipvsadm yum instal ...

  10. Zend Server安装后首次运行就出现Internal Server Error的解决(转)

    新近学习php,结果装了Zend Server上来就报错,网上找到了解决方法,照着做果然可行,转之. 刚才安装了Zend Server,安装后首次运行就爆出了一个Internal Server Err ...