对于今天比赛的总结

逆向,考虑增加一条边,将两个连通块合并了
考虑新连通块的直径与原来两个连通块直径的关系
设新连通块的直径端点为 x, y,原两个连通块的直径端点为a, b, c, d。
容易发现,x, y 一定是 a, b, c, d 其中之一。
除去原先两个连通块直径长度,乘上新连通块直径长度(除法需乘法逆元)
连通性用并查集维护,树上路径长度计算用 LCA+ 预处理前缀长度。
时间复杂度为 O(n log n)
(↑以上解释非原创!!!∑(゚Д゚ノ)ノ)
#include<iostream>
#include<cstdio>
using namespace std;
int N,f[1000001];
unsigned long long val[1000001],h[1000001],lng[1000001];
unsigned long long MOD=1000000007,e[1000001];
int top[1000001],heavy_son[1000001],q[1000001],F[1000001],dep[1000001],size[1000001],head[4000001];
unsigned long long total,c[1000001][3];
struct node{
    int l,r;
}a[1000001],b[1000001];
struct Node{
    int to,next;
}d[1000001];
int add(int u,int v){
    d[++N].to=v;
    d[N].next=head[u];
    head[u]=N;
    return 0;
}
int dad(int x){
    return f[x]==x ? x : f[x]=dad(f[x]);
}
unsigned long long inv(unsigned long long xx){
    return xx==1 ? 1 : ((MOD-MOD/xx)*inv(MOD%xx)+MOD)%MOD; 
}
int dfs1(int father,int root,int depth,unsigned long long val){
    lng[root]=val;
    F[root]=father;
    dep[root]=depth;
    size[root]=1;
    for(int i=head[root];i;i=d[i].next){
        int To=d[i].to;
        if(To==father) continue;
        dfs1(root,To,depth+1,val+h[To]);
        size[root]+=size[To];
        if(size[To]>size[heavy_son[root]]) heavy_son[root]=To;
    }
    return 0;
}
int dfs2(int father,int root,int Top){
    top[root]=Top;
    if(heavy_son[root]!=0) dfs2(root,heavy_son[root],Top);
    for(int i=head[root];i;i=d[i].next){
        int To=d[i].to;
        if(To==father||To==heavy_son[root]) continue;
        dfs2(root,To,To);
    }
    return 0;
}
int lca(int X,int Y){
    while(top[X]!=top[Y]){
        if(dep[top[X]]>dep[top[Y]]) X=F[top[X]];
        else Y=F[top[Y]];
    }
    return dep[X]<dep[Y] ? X : Y;
}
int main(){
    int n;
    cin>>n;
    total=1;
    for(int i=1;i<=n;i++){
        cin>>h[i];
        val[i]=h[i];
        total=(total*h[i])%MOD;
        b[i].l=i;
        b[i].r=i;
    }
    for(int i=1;i<=n-1;i++){
        cin>>a[i].l>>a[i].r;
        add(a[i].l,a[i].r);
        add(a[i].r,a[i].l);
    }
    for(int i=1;i<=n-1;i++) cin>>q[i];
    for(int i=1;i<=n;i++) f[i]=i;
    dfs1(0,1,1,h[1]);
    dfs2(1,1,1);
    e[n]=total;
    for(int i=n-1;i>=1;i--){
        int j=q[i];
        int dad1=dad(a[j].l);
        int dad2=dad(a[j].r);
        f[dad2]=dad1;
        int x1=b[dad1].l;
        int x2=b[dad1].r;
        int x3=b[dad2].l;
        int x4=b[dad2].r;
        unsigned long long maxn=0;
        int p1=0,p2=0;
        if(x1!=x2){
            int z=lca(x1,x2);
            if(lng[x1]+lng[x2]-2*lng[z]+h[z]>maxn){
                maxn=lng[x1]+lng[x2]-2*lng[z]+h[z];
                p1=x1;
                p2=x2;
            }
        }
        if(x1!=x3){
            int z=lca(x1,x3);
            if(lng[x1]+lng[x3]-2*lng[z]+h[z]>maxn){
                maxn=lng[x1]+lng[x3]-2*lng[z]+h[z];
                //cout<<;
                p1=x1;
                p2=x3;
            }
        }
        if(x1!=x4){
            int z=lca(x1,x4);
            if(lng[x1]+lng[x4]-2*lng[z]+h[z]>maxn){
                maxn=lng[x1]+lng[x4]-2*lng[z]+h[z];
                p1=x1;
                p2=x4;
            }
        }
        if(x2!=x3){
            int z=lca(x2,x3);
            if(lng[x3]+lng[x2]-2*lng[z]+h[z]>maxn){
                maxn=lng[x3]+lng[x2]-2*lng[z]+h[z];
                p1=x3;
                p2=x2;
            }
        }
        if(x2!=x4){
            int z=lca(x2,x4);
            if(lng[x4]+lng[x2]-2*lng[z]+h[z]>maxn){
                maxn=lng[x4]+lng[x2]-2*lng[z]+h[z];
                p1=x4;
                p2=x2;
            }
        }
        if(x3!=x4){
            int z=lca(x3,x4);
            if(lng[x3]+lng[x4]-2*lng[z]+h[z]>maxn){
                maxn=lng[x3]+lng[x4]-2*lng[z]+h[z];
                p1=x3;
                p2=x4;
            }
        }
        e[i]=e[i+1]*maxn%MOD*inv(val[dad1])%MOD*inv(val[dad2])%MOD;
        val[dad1]=maxn;
        b[dad1].l=p1;
        b[dad1].r=p2;
        
    }
    for(int i=1;i<=n;i++){
        cout<<e[i]<<'\n';
    }
    return 0;
}

T1

可以通过线性筛筛去 106 以下的质数。
如果此时剩下的数 x 不是 1,由于 c ≤ 1018,则必定是至多两个大于 106 的质数的乘积。
此时只要判断这两个质数是否相等即可,对 x 开根再平方看是否等于 x 即可。
(↑以上解释仍非原创!!!∑(゚Д゚ノ)ノ)
//来自King_8的代码(Genius改编)
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
int c[1000010],pri[1000010],N;
long long int n;
void Pri(){
    for(int i=2;i<=1000000;i++){
        if(c[i]==0){
            pri[++N]=i;
            for(int j=2;j*i<=1000000;j++) c[j*i]=1;
        }
    }
}
bool check(long long int x){
    int i=1;
    long long int j=sqrt(x);
    while(i<=N&&x!=1&&pri[i]<=j){
        if(x%pri[i]==0) x/=pri[i];
        while(x%pri[i]==0){
            x/=pri[i];
            return true;
        }
        i++;
    }
    j=sqrt(x);
    if(j*j==x&&x>1000000) return true;
    return false;
}
int main(){
    Pri();
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%lld",&n);
        if(check(n)) printf("yes\n");
        else printf("no\n");
    }
    
}

 

 
posted @ 2021-08-16 21:42  latent_Lin  阅读(37)  评论(0)    收藏  举报