# Barbecue【省选模拟赛】

## 分治后利用单调性two-pointers

Posted by yjjr's blog on April 13, 2018

# 题目

## 问题描述

Lyra 去野外旅游，准备试验刚买的烧烤架，于是她⾛到了附近的⼀棵树下想把树的⼀部分砍下来作为燃料。

# code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define mem(x,num) memset(x,num,sizeof x)
#define ll long long
#define reg(i,x) for(int i=last[x];i;i=e[i].next)
using namespace std;
inline ll read(){
ll f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
#define mid ((l+r)>>1)
const int maxn=3e5+6;
int T,n,cnt,last[maxn],fa[maxn],fl[maxn],fr[maxn],num[maxn];
struct edge{int to,next;}e[maxn<<2];
void insert(int u,int v){
e[++cnt]=(edge){v,last[u]};last[u]=cnt;
e[++cnt]=(edge){u,last[v]};last[v]=cnt;
}
void dfs(int l,int r,int x,int mnp,int mxp){
mnp=min(mnp,x),mxp=max(mxp,x);
fl[x]=mnp,fr[x]=mxp;
reg(i,x){
if(e[i].to==fa[x])continue;
if(e[i].to>=l&&e[i].to<=r){fa[e[i].to]=x;dfs(l,r,e[i].to,mnp,mxp);}
}
}//dfs处理出以mid为根的路径上的点的最值
inline ll solve(int l,int r){
if(l>r)return 0;if(l==r)return 1;
ll re=0;int jl,jr,fm;
rep(i,l,r){fl[i]=n+1;fr[i]=-1;}
fa[mid]=0;dfs(l,r,mid,mid,mid);num[mid-1]=1;fm=mid;
rep(i,mid,r){fm=max(fm,fr[i]);num[i]=(fm<=i)?num[i-1]+1:num[i-1];}
jl=jr=fm=mid;
for(int i=mid;i>=l&&(~fr[i]);i--){
fm=min(fm,fl[i]);jl=max(jl,fr[i]);
while(jr<=r&&fl[jr]>=i&&(~fr[jr]))jr++;
if(fm>=i&&jl<jr)re+=num[jr-1]-num[jl-1];
}//two-pointers单调不降求解
re+=solve(l,mid-1)+solve(mid+1,r);
return re;
}
int main(){
T=read();
while(T--){
n=read();
mem(last,0);cnt=0;
rep(i,1,n-1){
int u=read(),v=read();
insert(u,v);
}
printf("%lld\n",solve(1,n));
}
return 0;
}