zoukankan      html  css  js  c++  java
  • Codeforces Round #686 (Div. 3)

    Codeforces Round #686 (Div. 3)

    Codeforces Round #686 (Div. 3)

    E. Number of Simple Paths

    题意:给一颗基环树,问有多少条路径。

    题解:通过观察易发现,能经过环到达的点都可以走两条路,而在环上的一颗树上的两点都只有一条路径,所以我们可以算出每个点对都走两条路的答案,再减去树上的点对数即可,首先要找到环,我用dfs类似于求强连通分量的方法求出环上的点,在枚举环上有外接树的点用第二个dfs搜出树的大小,更新答案。

        #include<bits/stdc++.h>
        using namespace std;
        #define ll long long
        ll n,t;
        ll ishuan[200007];
        vector<ll>ho[200007];
        vector<ll>res;
        ll vs;
        ll vis[200007];
        ll fa[200007];
        void init(){
        	vs=0;
        	for(int i=1;i<=n;i++)vis[i]=0;
            for(int i=1;i<=n;i++){
            	ho[i].clear();
            	fa[i]=0;
                ishuan[i]=0;
            }
            res.clear();
        }
        void dfs(ll p,ll f){
        	vis[p]=++vs;
            for(int i=0;i<ho[p].size();i++){
                ll to=ho[p][i];
                if(to==f)continue;
                if(vis[to]){
                    if(vis[to]<vis[p])continue;
                    res.push_back(to);
                    ishuan[to]=1;
                    for(;to!=p;to=fa[to]){
                    	res.push_back(fa[to]);
                    	ishuan[fa[to]]=1;
                    }
                }
                else{
                	fa[to]=p;
                	dfs(to,p);
                }
            } 
        }
        ll cal(ll p,ll f){
        	ll sum=1;
        	for(ll i=0;i<ho[p].size();i++){
        		ll to=ho[p][i];
        		if(to==f)continue;
        		sum+=cal(to,p);
        	}
        	return sum;
        }
        int main(){
        	scanf("%lld",&t);
        	while(t--){
        		scanf("%lld",&n);
        	    init();
        	    for(int i=1;i<=n;i++){
        	        int a,b;
        	        cin>>a>>b;
        	        ho[a].push_back(b);
           			ho[b].push_back(a);
        	    }
        	    dfs(1,0);
        	    ll ans=n*(n-1);
        	    for(int i=0;i<res.size();i++){
        	    	int p=res[i];
        	    	ll sum=0;
        	        for(int j=0;j<ho[p].size();j++){
        	        	int to=ho[p][j];
        	        	if(ishuan[to]==0){
        	        		sum+=cal(to,p);
        	        		
        	        	}
        	        }
        	        ans-=sum*(sum+1)/2;
        	    }
        	    printf("%lld
    ",ans);
        	}
        }
    
    F. Array Partition

    题意:给一个区间,分成3个大小不为0的区间,使中间区间的最小值,等于两边区间的最大值。

    题解:首先枚举最左边的区间长度,并求出区间最大值x,可知最右边的区间至少要有一个x定下最右边区间的L的最大合法范围,同时我们知道中间区间不能有小于x的值,所以小于x的值要全给最右边的区间,用线段树二分查出最左边的小于x的值的位置于L的最大合法范围取min,作为最右段的L,再用线段树查询区间最值判断是否合法。

        #include<iostream>
        #include<map>
        using namespace std;
        int t,n,now,p,l,r;
        map<int,int>mp;
        struct madoka{
        	int l;
        	int r;
        	int mi;
        	int mx;
        }ma[2000007];
        void build(int l,int r,int k){
        	ma[k].l=l;
        	ma[k].r=r;
        	if(l==r){
        		scanf("%d",&ma[k].mi);
        		mp[ma[k].mi]=l;
        		ma[k].mx=ma[k].mi;
        		return;
        	}
        	int mid=(l+r)/2;
        	build(l,mid,k*2);
        	build(mid+1,r,k*2+1);
        	ma[k].mi=min(ma[k*2].mi,ma[k*2+1].mi);
        	ma[k].mx=max(ma[k*2].mx,ma[k*2+1].mx);
        	return;
        }
        int qry(int k,int l,int r,int z){
        	if(l<=ma[k].l&&ma[k].r<=r){
        		if(z==1){
        			return ma[k].mx;
        		}
        		else{
        			return ma[k].mi;
        		}
        	}
        	int mid=(ma[k].l+ma[k].r)/2;
        	int ans;
        	if(z)ans=0;
        	else ans=1e9;
        	if(mid>=l){
        		if(z)ans=max(qry(k*2,l,r,z),ans);
        		else ans=min(qry(k*2,l,r,z),ans);
        	}
        	if(mid<r){
        		if(z)ans=max(qry(k*2+1,l,r,z),ans);
        		else ans=min(qry(k*2+1,l,r,z),ans);
        	}
        	return ans;
        }
        int fin(int k,int l,int r){
        	if(ma[k].mi>=now){
        		return 1e9;
        	}
        	if(ma[k].l==ma[k].r){
        		return ma[k].l;
        	}
        	if(l<=ma[k].l&&ma[k].r<=r){
        		if(ma[k*2].mi>=now){
        			return fin(k*2+1,l,r);
        		}
        		else{
        			return fin(k*2,l,r);
        		}
        	}
        	int mid=(ma[k].l+ma[k].r)/2;
        	int mi=1e9;
        	if(mid>=l){
        		mi=min(mi,fin(k*2,l,r));
        	}
        	if(mid<r){
        		mi=min(mi,fin(k*2+1,l,r));
        	}
        	return mi;
        }
        int main(){
        	scanf("%d",&t);
        	while(t--){
        		mp.clear();
        		scanf("%d",&n);
        		build(1,n,1);
        		int a=0,b=0,c=0;
        		for(int i=1;i<=n-2;i++){
        			now=qry(1,1,i,1);
        			l=i+2;
        			r=mp[now];
        			if(l>r){
        				continue;
        			}
        			p=fin(1,l,r);
        			if(p==1e9){
        				p=r;
        			}
        			if(qry(1,i+1,p-1,0)==now&&now==qry(1,p,n,1)){
        				a=i,b=p-i-1,c=n-p+1;
        				break;
        			}
        		}
        		if(a+b+c==n){
        			printf("YES
    ");
        			printf("%d %d %d
    ",a,b,c);
        		}
        		else{
        			printf("NO
    ");
        		}
        		
        	}
        }
    
  • 相关阅读:
    AtCoder Beginner Contest 167
    AtCoder Beginner Contest 166
    AtCoder Beginner Contest 165
    AtCoder Beginner Contest 164
    AtCoder Beginner Contest 163
    AtCoder Beginner Contest 162
    AtCoder Beginner Contest 161
    AtCoder Beginner Contest 160
    AtCoder Beginner Contest 159
    自定义Mybatis自动生成代码规则
  • 原文地址:https://www.cnblogs.com/whitelily/p/14036563.html
Copyright © 2011-2022 走看看