[Lydsy1806月赛] 路径统计

题面在这里!

 

xjb想的做法竟然不小心把std艹爆了qwq,我也很无奈啊....

 

 

    那接下来就说一下我的神奇做法qwq

    如果是经常读我博客的童鞋会发现其实我以前就想要做这个题啦,只不过当时读错题啦。。。以为[L,R]在树上只要形成联通块就可以了,于是就自己出了一个题

   

    那个题的做法是直接扫描线,因为[L,R]合法当且仅当 R-L = sum[L] ,其中sum[L] 表示以L 为左端点,目前扫描线为右端点的区间中在树上相邻的点对数,而扫描线右端点右移一位造成的影响只会是一些前缀的sum[]区间加,用线段树动态维护一下就好啦。(维护 区间加,最大值和其数量)

    于是那个题就这么做完了。。。。

 

    但是这个题还得要求 在树上形成的联通块是一个链。。。。。

    不过仔细想想,链无非就比联通块多一个限制:所有点的度数<=2

    所以我们就可以对于每个扫描线右端点R,去动态维护一个L,使得区间 [L,R] 在树上是若干链(当然也可以是一条啦),但是 [L-1,R]的点构成的子图中就有至少一个点的度数>2了。

    不难想到 L 关于 R 是具有单调性的,R增大L不会变小,并且 [L,R] 满足没有 >2的度数的点的话,[L+1,R]也满足;反之,[L,R]不满足的话那么 [L-1,R] 也不满足。。。。

    所以就可以用度数的关系轻松的O(N)维护这个玩意,复杂度还是在扫描线线段树那里。

 

    于是这个题也这么做完了23333

 

#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define pb push_back
#define lc (o<<1)
#define mid (l+r>>1)
#define rc ((o<<1)|1)
const int N=250005;

inline int read(){
	int x=0; char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
	return x;
}

vector<int> g[N],h[N];
int mx[N*4],tag[N*4],n,m,le,ri;
int dg[N],num,L,sum[N*4],M,cnt,R;
ll ans=0;

inline void mt(int o){
	mx[o]=max(mx[lc],mx[rc]);
	sum[o]=(mx[lc]==mx[o]?sum[lc]:0)+(mx[rc]==mx[o]?sum[rc]:0);
}

inline void work(int o,int der){ tag[o]+=der,mx[o]+=der;}

inline void pd(int o){
	if(tag[o]){
		work(lc,tag[o]),work(rc,tag[o]);
		tag[o]=0;
	}
}

void build(int o,int l,int r){
	sum[o]=1,mx[o]=r;
	if(l==r) return;
	build(lc,l,mid),build(rc,mid+1,r);
}

void update(int o,int l,int r){
	if(l>=le&&r<=ri){ work(o,1); return;}
	pd(o);
	if(le<=mid) update(lc,l,mid);
	if(ri>mid) update(rc,mid+1,r);
	mt(o);
}

void query(int o,int l,int r){
	if(l>=le&&r<=ri){
		if(mx[o]>M) M=mx[o],cnt=sum[o];
		else if(mx[o]==M) cnt+=sum[o];
		return;
	}

	pd(o);

	if(le<=mid) query(lc,l,mid);
	if(ri>mid) query(rc,mid+1,r);
}

inline void ADD(int x){
	le=1;
	for(int j=g[x].size()-1,i;j>=0;j--){
		i=g[x][j],ri=i,update(1,1,n);
		if(i>=L) num+=((++dg[x])==3)+((++dg[i])==3);
	}
}

inline void Del(int x){
	for(int j=h[x].size()-1,i;j>=0;j--){
		i=h[x][j];
		if(i<=R) num-=((--dg[x])==2)+((--dg[i])==2);
	}
}

inline void solve(){
	build(1,1,n),L=1;

	for(int i=1;i<=n;i++){
		ADD(i),R=i;
		for(;num;L++) Del(L);

		le=L,ri=i,M=0,query(1,1,n);
		if(M==i) ans+=(ll)cnt;
	}
}

int main(){
	n=read();
	for(int i=1,uu,vv;i<n;i++){
		uu=read(),vv=read();
		if(uu<vv) g[vv].pb(uu),h[uu].pb(vv);
		else g[uu].pb(vv),h[vv].pb(uu);
	}
	solve(),printf("%lld\n",ans);
	return 0;
}

 

posted @ 2018-07-13 10:09  蒟蒻JHY  阅读(542)  评论(2编辑  收藏  举报