40分求助(带详细注释)
查看原帖
40分求助(带详细注释)
173397
取啥名好楼主2020/9/23 13:35

对两个错两个T一个,但算法是线性的,也用了快读快输。基础版的是60分,后面大数据反而过了1,3两点错了,该开longlong的也开了,实在找不到哪里有问题。

#include<bits/stdc++.h>
using namespace std;
int n,a,b,cnt=0,jl[3000010]={0},col[3000010]={0},sum[3000010]={0},head[6000010]={0};
int js[3000010]={0},bian[6000010]={0};
bool mark[3000010]={0};
struct node{int to,next;}tu[6000010]={0};
vector<int> v[3000010];
inline int r(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return x*f;
}
inline void w(long long X){
	int s[20],top=0;
	while(X) {s[++top]=X%10; X/=10;}
	if(!top) s[++top]=0;
	while(top) putchar(s[top--]+'0');
}
int pre_dfs(int x,int fa){sum[col[x]]++;
    int num=1,temp,pre_jl=sum[col[x]],last=0;    
    for(int i=head[x];i;i=tu[i].next){
        if(tu[i].to==fa)continue;
        temp=pre_dfs(tu[i].to,x);
        if(pre_jl!=sum[col[x]])last=tu[i].to;
        bian[i]=temp;num+=temp;
        if(i%2)bian[i+1]=n-temp;
        else bian[i-1]=n-temp;//bian是记录该边所连的点为根的子树大小,去的bian的大小就是子树大小,回来的就是n-子树大小。边从1开始存,所以要这样处理。
    }
    if(mark[col[x]])    return num;
    else if(sum[col[x]]==jl[col[x]]&&pre_jl==1)v[col[x]].push_back(x),js[x]=last;//如果本来一个点都没扫到,现在扫到的点数又等于所有该颜色点的个数,那这个点一定是一个端点
    else if(sum[col[x]]==pre_jl)v[col[x]].push_back(x),js[x]=fa;//如果下面没有该颜色的点,那这个点也是端点
    //js纪录的是通往链中间那坨的点,在后面计算答案要排除的
    if(v[col[x]].size()>2)mark[col[x]]=1;
    return num;
}
void solve_1(int x){
    queue<int> q;long long sum=0,ans=0,temp;
    for(int i=head[x];i;i=tu[i].next)
        q.push(bian[i]),sum+=bian[i];
    while(!q.empty()){
        temp=q.front();q.pop();
        sum-=temp;ans+=sum*temp;
    }w(ans+(n-1));cout<<endl;
}//所有子树两两乘积和+n-1
void solve_2(int x,int y){
    long long sum_x=1,sum_y=1;
    for(int i=head[x];i;i=tu[i].next)
        if(tu[i].to!=js[x])sum_x+=bian[i];
    for(int i=head[y];i;i=tu[i].next)
        if(tu[i].to!=js[y])sum_y+=bian[i];
    w(sum_x*sum_y);cout<<endl;
}//去掉中间一坨点后,剩下两颗子树的大小乘积
void add(int u,int v){
    cnt++;tu[cnt].to=v;tu[cnt].next=head[u];head[u]=cnt;
    cnt++;tu[cnt].to=u;tu[cnt].next=head[v];head[v]=cnt;
}
int main(){
    n=r();for(int i=1;i<=n;i++)col[i]=r(),jl[col[i]]++;//记录每种颜色的点数
    for(int i=1;i<n;i++)a=r(),b=r(),add(a,b);
    pre_dfs(1,0);for(int i=1;i<=n;i++){
        if(mark[i])cout<<0<<endl;
        if(v[i].size()==1)solve_1(v[i][0]);
        if(v[i].size()==0){w((1ll*n*(n-1))/2);cout<<endl;}
        if(v[i].size()==2)solve_2(v[i][0],v[i][1]);
        //分类讨论
    }
    system("pause");return 0;
}
2020/9/23 13:35
加载中...