zoukankan      html  css  js  c++  java
  • UOJ #192 【UR #14】 最强跳蚤

    题目链接:最强跳蚤

      这道题本来不想写博客的……但是鉴于自己犯了低级错误,还是写篇博客记载一下。

      一开始我的想法和题解里面的算法而比较类似,也是先分解质因数,然后用质因子是否出现偶数次来判断当前这个数是否是完全平方数……

      然而这样并不能AC,于是我去翻了题解……(get)了一个新做法,就是给每个出现过的质因子赋一个([0,2^{64}))的随机值,那么判断一个质因子是否出现偶数次就只需要判断异或和是否为零了。算一算可以发现冲突的概率非常小(但是我不会算)。

      然后……我就愉快的写了一发树分治……就当我练了一发板子好了(正好保存一份树分治板子)……

      下面贴代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    #define maxn 100010
    #define maxp 10010
    #define mod 999983
     
    using namespace std;
    typedef unsigned long long llg;
     
    int pri[maxp],lp,a[maxn],la,n,d[maxn];
    int head[maxn],next[maxn<<1],to[maxn<<1],tt;
    int w[maxn],siz[maxn],maxv[maxn],ld;
    int h1[mod],n1[mod],ci[mod],_t,hd[mod],_d;
    llg c1[maxn],val[maxn],c[maxn<<1],ans,INF,t1[mod];
    bool vis[maxn];
     
    int getint(){
        int w=0;bool q=0;
        char c=getchar();
        while((c>'9'||c<'0')&&c!='-') c=getchar();
        if(c=='-') c=getchar(),q=1;
        while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
        return q?-w:w;
    }
     
    llg ra(){llg x=(llg)rand()*(llg)rand()+(llg)rand();return x==INF?ra():x;}
    void link(int x,int y){
        to[++tt]=y;next[tt]=head[x];head[x]=tt;
        to[++tt]=x;next[tt]=head[y];head[y]=tt;
    }
     
    void pre(){
        for(int i=2;i<maxp;i++){
            if(!vis[i]) pri[++lp]=i;
            for(int j=1;j<=lp && pri[j]*i<maxp;j++){
                vis[pri[j]*i]=1;
                if(!(i%pri[j])) break;
            }
        }
        for(int i=1;i<=lp;i++) val[i]=ra();
    }
     
    void dfs1(int u,int fa){
        siz[u]=1; maxv[u]=0; d[++ld]=u;
        for(int i=head[u],v;v=to[i],i;i=next[i])
            if(!vis[v] && v!=fa){
                dfs1(v,u),siz[u]+=siz[v];
                maxv[u]=max(maxv[u],siz[v]);
            }
    }
     
    void dfs2(int u,llg now){
        vis[u]=1; c1[++ld]=now; if(!now) ans++;
        for(int i=head[u],v;v=to[i],i;i=next[i])
            if(!vis[v]) dfs2(v,now^c[i]);
        vis[u]=0;
    }
     
    int find(llg x){
        int u=x%mod;
        for(int i=h1[u];i;i=n1[i])
            if(t1[i]==x) return i;
        return 0;
    }
     
    int insert(llg x){
        int j=find(x);
        if(j){ci[j]++;return j;}
        int u=x%mod; hd[++_d]=u; ci[++_t]=1;
        t1[_t]=x; n1[_t]=h1[u];h1[u]=_t;
        return _t;
    }
     
    void solve(int u){
        ld=0; dfs1(u,0); int _k=n+1,k;
        for(int i=1,l,x;l=d[i],i<=ld;i++){
            x=max(maxv[l],siz[u]-siz[l]);
            if(x<_k) _k=x,k=l;
        }
        vis[k]=1; ld=_d=0;
        for(int i=head[k];i;i=next[i])
            if(!vis[to[i]]){
                ld=0; dfs2(to[i],c[i]); sort(c1+1,c1+ld+1);
                for(int j=1,k;k=j,j<=ld;j=k+1){
                    while(k<ld && c1[k+1]==c1[j]) k++;
                    ans+=(llg)(ci[find(c1[j])])*(llg)(k-j+1);
                }
                for(int j=1,k,x;k=j,j<=ld;j=k+1){
                    while(k<ld && c1[k+1]==c1[j]) k++;
                    x=insert(c1[j]); ci[x]+=k-j;
                }
            }
        for(int i=1;i<=_d;i++) h1[hd[i]]=0; _t=0;
        for(int i=head[k];i;i=next[i])
            if(!vis[to[i]]) solve(to[i]);
    }
     
    int main(){
        File("a");
        pre(); n=getint(); INF--;
        for(int i=1,pos;i<n;i++){
            link(getint(),getint());
            w[i]=getint();
            for(int j=1;pri[j]*pri[j]<=w[i];j++){
                pos=0;
                while(!(w[i]%pri[j]))
                    w[i]/=pri[j],pos^=1;
                if(pos) c[tt]^=val[j];
            }
            if(w[i]!=1 && w[i]<maxp) c[tt]^=val[lower_bound(pri+1,pri+lp+1,w[i])-pri],w[i]=1;
            if(w[i]!=1) a[++la]=w[i]; c[tt-1]=c[tt];
        }
        sort(a+1,a+la+1); la=unique(a+1,a+la+1)-a-1;
        for(int i=1;i<=la;i++) val[i]=ra();
        for(int i=1;i<n;i++)
            if(w[i]>1){
                c[i<<1]^=val[lower_bound(a+1,a+la+1,w[i])-a];
                c[i*2-1]=c[i<<1];
            }
        for(int i=1;i<maxp;i++) vis[i]=0; solve(1);
        printf("%lld
    ",ans<<1);
        return 0;
    }
    

       这道题既然是要异或和为零,那么何必树分治呢?我们只需(dfs)一遍,记录每个节点到根的异或和,然后两个节点之间的异或和就可以由这两个节点到根的异或和异或得到。因为(lca)上面那一截会消掉……

      这已经不是第一次犯这种低级错误了,所以我在这里记录下来。代码比之前短了很多,也快了很多,感人(强行增加复杂度我就是个(zz))

      下面贴代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    #define maxn 100010
    #define maxp 10010
    #define mod 999983
    
    using namespace std;
    typedef unsigned long long llg;
    
    int pri[maxp],lp,a[maxn],la,n,w[maxn],ld;
    int head[maxn],next[maxn<<1],to[maxn<<1],tt;
    llg c[maxn<<1],ans,val[maxn],d[maxn];
    bool vis[maxn];
    
    int getint(){
    	int w=0;bool q=0;
    	char c=getchar();
    	while((c>'9'||c<'0')&&c!='-') c=getchar();
    	if(c=='-') c=getchar(),q=1;
    	while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
    	return q?-w:w;
    }
    
    llg ra(){return (llg)rand()*(llg)rand()+(llg)rand();}
    void link(int x,int y){
    	to[++tt]=y;next[tt]=head[x];head[x]=tt;
    	to[++tt]=x;next[tt]=head[y];head[y]=tt;
    }
    
    void pre(){
    	for(int i=2;i<maxp;i++){
    		if(!vis[i]) pri[++lp]=i;
    		for(int j=1;j<=lp && pri[j]*i<maxp;j++){
    			vis[pri[j]*i]=1;
    			if(!(i%pri[j])) break;
    		}
    	}
    	for(int i=1;i<=lp;i++) val[i]=ra();
    }
    
    void dfs(int u,int fa,llg now){
    	d[++ld]=now;
    	for(int i=head[u],v;v=to[i],i;i=next[i])
    		if(v!=fa) dfs(v,u,now^c[i]);
    }
    
    int main(){
    	File("a");
    	pre(); n=getint();
    	for(int i=1,pos;i<n;i++){
    		link(getint(),getint());
    		w[i]=getint();
    		for(int j=1;pri[j]*pri[j]<=w[i];j++){
    			pos=0;
    			while(!(w[i]%pri[j]))
    				w[i]/=pri[j],pos^=1;
    			if(pos) c[tt]^=val[j];
    		}
    		if(w[i]!=1 && w[i]<maxp) c[tt]^=val[lower_bound(pri+1,pri+lp+1,w[i])-pri],w[i]=1;
    		if(w[i]!=1) a[++la]=w[i]; c[tt-1]=c[tt];
    	}
    	sort(a+1,a+la+1); la=unique(a+1,a+la+1)-a-1;
    	for(int i=1;i<=la;i++) val[i]=ra();
    	for(int i=1;i<n;i++)
    		if(w[i]>1){
    			c[i<<1]^=val[lower_bound(a+1,a+la+1,w[i])-a];
    			c[i*2-1]=c[i<<1];
    		}
    	dfs(1,0,0); sort(d+1,d+ld+1);
    	for(int i=1,j;j=i,i<=ld;i=j+1){
    		while(j<ld && d[j+1]==d[i]) j++;
    		ans+=(llg)(j-i)*(llg)(j-i+1);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Python课程第三天作业
    Python课程第一天作业
    centos7安装Jenkins
    搭建zookeeper+kafka集群
    redis在实践中的一些常见问题以及优化思路
    部署redis4.0-cluster
    redis哨兵架构的基础知识及部署和管理
    Redis主从复制
    部署Redis4.x单机版及配置RDB和AOF持久化
    xshell使用密钥登陆linux
  • 原文地址:https://www.cnblogs.com/lcf-2000/p/6287831.html
Copyright © 2011-2022 走看看