zoukankan      html  css  js  c++  java
  • CodeForces

    题目:https://vjudge.net/contest/307753#problem/J

    题意:一棵树,每个点都有个权值,现在问你,树上gcd每个不同的数有多少个

    思路:点分治,首先范围只有 1e5,然后我们记录一条路径的gcd,我们在重心确定后找路径,每到gcd一个数,这条路径必然是父亲节点的因子,一个数的因子不同的个数很少,其实就相当于是几个数的不同因子数,所以gcd路径不同的个数肯定很少,我们就可以在遍历子树的时候直接暴力之前出现过的路径值了,复杂度 应该是 O(n*logn*logn)的,

    这题时间卡的特别紧,我本来使用map记录不同数的个数,发现超时,我认为是多了个log的原因,我就改成了链表O(1)取,但是仔细想想其实map的log其实是按节点数来的,我gcd不同的数很少,其实这个log趋近于O(1),真正的原因-输入挂(坑的死)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<iostream> 
    #include<vector>
    #include<queue>
    #include<map>
    #define maxn 200005
    #define mod 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    struct edge{
        int to,next;
    }e1[2*maxn];
    struct node{
        ll next;
        ll val;
        ll bj;
    }flag[maxn];
    ll da;
    vector<ll> mp[maxn],xx[maxn];//存下图 
    ll e[maxn];
    ll e2[20*maxn];
    bool vis[maxn];//标记曾经使用过的重心 
    ll maxsize[maxn],dis[maxn],d[maxn],yj[maxn],last[maxn];//maxsize 当前节点的最大子树 
    ll siz[maxn],xd[maxn];// dis 到重心的距离  d 出现过的距离 
    ll n,m,k,rt,sum,qe,qe2,ans1,ans2,cnt,head;  // siz 当前节点的子树个数  e 出现的距离  rt代表当前重心 
    inline void read(ll &x) {
        x=0; char c=getchar();
        while(c>'9'||c<'0') c=getchar();
        while(c<='9'&&c>='0') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    }
    void find(ll x,ll f){//找出重心 
        siz[x]=1;
        maxsize[x]=0;
        for(int i=last[x];i;i=e1[i].next){
            ll v=e1[i].to;
            if(v==f||vis[v]) continue;//vis数组标记曾经使用过的重心 
            find(v,x);
            siz[x]+=siz[v];
            maxsize[x]=max(maxsize[x],siz[v]); 
        } 
        maxsize[x]=max(maxsize[x],sum-siz[x]);//节点总数减去当前的子树数=以当前节点为根的父亲点子树数 
        if(maxsize[x]<maxsize[rt]){
            rt=x;
        } 
    }
    void insert(int u,int v)
    {
        e1[++cnt].to=v;e1[cnt].next=last[u];last[u]=cnt;
        e1[++cnt].to=u;e1[cnt].next=last[v];last[v]=cnt;
    }
    void get_dis(ll x,ll f,ll len,ll root){
        
        yj[len]++;
        ll t=head;
        while(t!=-1){
            yj[__gcd(t,len)]+=flag[t].val;
            t=flag[t].next;
        }
        e[qe]=len;
        qe++;
        for(int i=last[x];i;i=e1[i].next){
            ll v=e1[i].to;
            if(v==f||vis[v]) continue;
            //dis[q.first]=(dis[x]+len)%3;
            get_dis(v,x,__gcd(len,xd[v]),root);
        }    
    }
    void divide(ll x){
        vis[x]=1;
        //printf("rt=%lld ans1=%lld
    ",x,ans1);
        for(int i=last[x];i;i=e1[i].next){
            ll v=e1[i].to;
            qe=0;
            if(vis[v]) continue;
            //dis[x]=q.second;
            get_dis(v,x,__gcd(xd[x],xd[v]),x);
            for(int j=0;j<qe;j++){
                if(head==-1){
                    head=e[j];
                    flag[e[j]].val=1;
                    flag[e[j]].next=-1;
                    flag[e[j]].bj=1;
                }
                else if(flag[e[j]].bj==0){
                    flag[e[j]].val=1;
                    flag[e[j]].next=head;
                    flag[e[j]].bj=1;
                    head=e[j];
                }
                else{
                    flag[e[j]].val++;
                }
            }
        }
        ll t=head;
        while(t!=-1){
            flag[t].bj=0;
            t=flag[t].next;
        }
        head=-1;
        //qe2=0;
        for(int i=last[x];i;i=e1[i].next){
            ll q=e1[i].to;
            if(vis[q]) continue;
            //if(da>0) break;
            sum=siz[q];
            rt=0;
            maxsize[rt]=mod;
            find(q,x);
            divide(rt);
        }
    //    vis[x]=0;
    }
    void init(){
        ans1=0;ans2=0;
        head=-1;
        //for(int i=0;i<=n+1;i++) mp[i].clear();
        for(int i=0;i<=n+1;i++) vis[i]=0;
        //for(int i=0;i<=n+1;i++) flag[i]=0;
        for(int i=0;i<=n+1;i++) yj[i]=0;
    } 
    int main(){
        ll t;
        read(n);
            ll a,b,c;
            init();
            ll xx;
            for(int i=1;i<=n;i++){
              read(xd[i]);
              yj[xd[i]]++;
            }
            for(int i=1;i<=n-1;i++){
                read(a);
                read(b);
                 insert(a,b);
            }
            sum=n;//当前节点数 
            rt=0;
            maxsize[0]=mod;//置初值 
            find(1,0);
            divide(rt);
            for(int i=1;i<maxn;i++){
                if(yj[i]==0) continue;
                cout<<i<<" "<<yj[i]<<"
    ";
                //printf("%I64d %I64d
    ",i,yj[i]);    
            }
    } 
  • 相关阅读:
    aspx页面按钮写返回上一页代码
    Javascript呼叫.axd文档
    获取GridView TemplateField的数据
    对象失去焦点时自己动提交数据 V2
    从图片路径获取图片尺寸
    双击一个图片然后跳转到另一个页面去
    Javascript alert消息换行
    ASP.NET播放Flash(.SWF)视频
    绑定List<T>到asp:Table控件
    Linux系统下的多线程编程条件变量&信号量
  • 原文地址:https://www.cnblogs.com/Lis-/p/11370670.html
Copyright © 2011-2022 走看看