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
");
}
}
}