• [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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Populating Next Right Pointers in Each Node II
    Populating Next Right Pointers in Each Node
    Construct Binary Tree from Preorder and Inorder Traversal
    Construct Binary Tree from Inorder and Postorder Traversal
    Path Sum
    Symmetric Tree
    Solve Tree Problems Recursively
    632. Smallest Range(priority_queue)
    609. Find Duplicate File in System
    poj3159最短路spfa+邻接表
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9303423.html
Copyright © 2020-2023  润新知